core/includes/theme.inc | 26 ++--
core/lib/Drupal/Core/Ajax/AjaxResponse.php | 12 +-
core/lib/Drupal/Core/Asset/AssetResolver.php | 144 +++++----------------
.../Drupal/Core/Asset/AssetResolverInterface.php | 89 ++-----------
core/lib/Drupal/Core/Asset/AttachedAssets.php | 95 ++++++++++++++
.../Drupal/Core/Asset/AttachedAssetsInterface.php | 85 ++++++++++++
core/modules/locale/locale.module | 5 +-
core/modules/simpletest/simpletest.module | 3 +-
.../system/src/Tests/Ajax/FrameworkTest.php | 20 +--
.../system/src/Tests/Common/AttachedAssetsTest.php | 85 ++++++------
core/modules/system/system.module | 18 +--
.../tests/modules/common_test/common_test.module | 4 +-
core/modules/system/theme.api.php | 12 +-
core/modules/user/user.module | 3 +-
14 files changed, 326 insertions(+), 275 deletions(-)
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index af3b6fa..8bd1818 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -15,6 +15,7 @@
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Component\Utility\Xss;
+use Drupal\Core\Asset\AttachedAssets;
use Drupal\Core\Config\Config;
use Drupal\Core\Config\StorageException;
use Drupal\Core\Extension\Extension;
@@ -1403,27 +1404,20 @@ function template_preprocess_html(&$variables) {
// Render the attachments into HTML markup to be used directly in the template
// for #type => html: html.html.twig.
$all_attached = ['#attached' => $attached];
-
- // Optimize CSS/JS if necessary, but only during normal site operation.
- $optimize_css = !defined('MAINTENANCE_MODE') && \Drupal::config('system.performance')->get('css.preprocess');
- $optimize_js = !defined('MAINTENANCE_MODE') && \Drupal::config('system.performance')->get('js.preprocess');
-
- // Resolve the attached libraries into asset collections.
- $asset_resolver = \Drupal::service('asset.resolver');
- $asset_resolver->setLibraries($all_attached['#attached']['library']);
+ $assets = AttachedAssets::createFromRenderArray($all_attached);
// Take Ajax page state into account, to allow for something like Turbolinks
// to be implemented without altering core.
// @see https://github.com/rails/turbolinks/
$ajax_page_state = \Drupal::request()->request->get('ajax_page_state');
- $asset_resolver->setAlreadyLoadedLibraries(isset($ajax_page_state) ? explode(',', $ajax_page_state['libraries']) : []);
- if (isset($all_attached['#attached']['drupalSettings'])) {
- $asset_resolver->setSettings($all_attached['#attached']['drupalSettings']);
- }
-
+ $assets->setAlreadyLoadedLibraries(isset($ajax_page_state) ? explode(',', $ajax_page_state['libraries']) : []);
+ // Optimize CSS/JS if necessary, but only during normal site operation.
+ $optimize_css = !defined('MAINTENANCE_MODE') && \Drupal::config('system.performance')->get('css.preprocess');
+ $optimize_js = !defined('MAINTENANCE_MODE') && \Drupal::config('system.performance')->get('js.preprocess');
// Render the asset collections.
- $variables['styles'] = \Drupal::service('asset.css.collection_renderer')->render($asset_resolver->getCssAssets($optimize_css));
- $variables['scripts'] = \Drupal::service('asset.js.collection_renderer')->render($asset_resolver->getJsAssetsForHeader($optimize_js));
- $variables['scripts_bottom'] = \Drupal::service('asset.js.collection_renderer')->render($asset_resolver->getJsAssetsForFooter($optimize_js));
+ $asset_resolver = \Drupal::service('asset.resolver');
+ $variables['styles'] = \Drupal::service('asset.css.collection_renderer')->render($asset_resolver->getCssAssets($assets, $optimize_css));
+ $variables['scripts'] = \Drupal::service('asset.js.collection_renderer')->render($asset_resolver->getJsAssetsForHeader($assets, $optimize_js));
+ $variables['scripts_bottom'] = \Drupal::service('asset.js.collection_renderer')->render($asset_resolver->getJsAssetsForFooter($assets, $optimize_js));
// Handle all non-asset attachments.
drupal_process_attached($all_attached);
diff --git a/core/lib/Drupal/Core/Ajax/AjaxResponse.php b/core/lib/Drupal/Core/Ajax/AjaxResponse.php
index 51c7e72..524e48e 100644
--- a/core/lib/Drupal/Core/Ajax/AjaxResponse.php
+++ b/core/lib/Drupal/Core/Ajax/AjaxResponse.php
@@ -7,6 +7,7 @@
namespace Drupal\Core\Ajax;
+use Drupal\Core\Asset\AttachedAssets;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -124,13 +125,14 @@ protected function ajaxRender(Request $request) {
$optimize_js = !defined('MAINTENANCE_MODE') && $config->get('js.preprocess');
// Resolve the attached libraries into asset collections.
- $asset_resolver = \Drupal::service('asset.resolver');
- $asset_resolver->setLibraries(isset($this->attachments['library']) ? $this->attachments['library'] : [])
+ $assets = new AttachedAssets();
+ $assets->setLibraries(isset($this->attachments['library']) ? $this->attachments['library'] : [])
->setAlreadyLoadedLibraries(isset($ajax_page_state) ? explode(',', $ajax_page_state['libraries']) : [])
->setSettings(isset($this->attachments['drupalSettings']) ? $this->attachments['drupalSettings'] : []);
- $css_assets = $asset_resolver->getCssAssets($optimize_css);
- $js_assets_header = $asset_resolver->getJsAssetsForHeader($optimize_js);
- $js_assets_footer = $asset_resolver->getJsAssetsForFooter($optimize_js);
+ $asset_resolver = \Drupal::service('asset.resolver');
+ $css_assets = $asset_resolver->getCssAssets($assets, $optimize_css);
+ $js_assets_header = $asset_resolver->getJsAssetsForHeader($assets, $optimize_js);
+ $js_assets_footer = $asset_resolver->getJsAssetsForFooter($assets, $optimize_js);
// Render the HTML to load these files, and add AJAX commands to insert this
// HTML in the page. Settings are handled separately, afterwards.
diff --git a/core/lib/Drupal/Core/Asset/AssetResolver.php b/core/lib/Drupal/Core/Asset/AssetResolver.php
index e2f824a..6d88391 100644
--- a/core/lib/Drupal/Core/Asset/AssetResolver.php
+++ b/core/lib/Drupal/Core/Asset/AssetResolver.php
@@ -44,13 +44,6 @@ class AssetResolver implements AssetResolverInterface {
protected $themeManager;
/**
- * The (ordered) list of asset libraries attached to the current response.
- *
- * @var string[]
- */
- protected $libraries = [];
-
- /**
* $libraries, along with all the depended asset libraries.
*
* @var string[]
@@ -58,13 +51,6 @@ class AssetResolver implements AssetResolverInterface {
protected $librariesWithDependencies = [];
/**
- * The set of asset libraries that the client has already loaded.
- *
- * @var string[]
- */
- protected $alreadyLoadedLibraries = [];
-
- /**
* $alreadyLoadedLibraries, along with all the depended asset libraries.
*
* @var string[]
@@ -72,13 +58,6 @@ class AssetResolver implements AssetResolverInterface {
protected $alreadyLoadedLibrariesWithDependencies = [];
/**
- * The JavaScript settings attached to the current response.
- *
- * @var array
- */
- protected $settings = [];
-
- /**
* Static cache of the JavaScript assets attached to the current response.
*
* @see reset()
@@ -108,73 +87,6 @@ public function __construct(LibraryDiscoveryInterface $library_discovery, Librar
}
/**
- * {@inheritdoc}
- */
- public function setLibraries(array $libraries) {
- $this->libraries = array_unique($libraries);
- $this->librariesWithDependencies = $this->libraryDependencyResolver->getLibrariesWithDependencies($this->libraries);
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getLibraries() {
- return $this->libraries;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getLibrariesWithDependencies() {
- return $this->librariesWithDependencies;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setAlreadyLoadedLibraries(array $libraries) {
- $this->alreadyLoadedLibraries = $libraries;
- $this->alreadyLoadedLibrariesWithDependencies = $this->libraryDependencyResolver->getLibrariesWithDependencies($this->alreadyLoadedLibraries);
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getAlreadyLoadedLibraries() {
- return $this->alreadyLoadedLibraries;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getAlreadyLoadedLibrariesWithDependencies() {
- return $this->alreadyLoadedLibrariesWithDependencies;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setSettings(array $settings) {
- $this->settings = $settings;
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function reset() {
- $this->libraries = [];
- $this->librariesWithDependencies = [];
- $this->settings = [];
- $this->alreadyLoadedLibraries = [];
- $this->alreadyLoadedLibrariesWithDependencies = [];
- $this->jsAssets = NULL;
- return $this;
- }
-
- /**
* Given lists of needed & loaded libraries, resolve which libraries to load.
*
* For example, with core/a depending on core/c and core/b on core/d:
@@ -184,24 +96,30 @@ public function reset() {
* $asset_resolver->getLibrariesToLoad() === ['core/a', 'core/b', 'core/d']
* @endcode
*
+ * @param \Drupal\Core\Asset\AttachedAssetsInterface $assets
+ * The assets attached to the current response.
+ *
* @return string[]
* A list of libraries, in the order they should be loaded, including their
* dependencies. (Any libraries that have already been loaded, and their
* dependencies, are excluded.)
*/
- protected function getLibrariesToLoad() {
- return array_diff($this->getLibrariesWithDependencies(), $this->getAlreadyLoadedLibrariesWithDependencies());
+ protected function getLibrariesToLoad(AttachedAssetsInterface $assets) {
+ return array_diff(
+ $this->libraryDependencyResolver->getLibrariesWithDependencies($assets->getLibraries()),
+ $this->libraryDependencyResolver->getLibrariesWithDependencies($assets->getAlreadyLoadedLibraries())
+ );
}
/**
* {@inheritdoc}
*/
- public function getCssAssets($optimize) {
+ public function getCssAssets(AttachedAssetsInterface $assets, $optimize) {
$theme_info = $this->themeManager->getActiveTheme();
$css = [];
- foreach ($this->getLibrariesToLoad() as $library) {
+ foreach ($this->getLibrariesToLoad($assets) as $library) {
list($extension, $name) = explode('/', $library, 2);
$definition = $this->libraryDiscovery->getLibraryByName($extension, $name);
if (isset($definition['css'])) {
@@ -250,8 +168,8 @@ public function getCssAssets($optimize) {
}
// Allow modules and themes to alter the CSS assets.
- $this->moduleHandler->alter('css', $css);
- $this->themeManager->alter('css', $css);
+ $this->moduleHandler->alter('css', $css, $assets);
+ $this->themeManager->alter('css', $css, $assets);
// Sort CSS items, so that they appear in the correct order.
uasort($css, 'static::sort');
@@ -283,8 +201,8 @@ public function getCssAssets($optimize) {
/**
* {@inheritdoc}
*/
- public function getJsAssetsForHeader($optimize) {
- $js_assets = $this->getJsAssets();
+ public function getJsAssetsForHeader(AttachedAssetsInterface $assets, $optimize) {
+ $js_assets = $this->getJsAssets($assets);
// Filter out elements of the given scope.
$js_assets_header = array();
@@ -299,10 +217,11 @@ public function getJsAssetsForHeader($optimize) {
// If the core/drupalSettings library is being loaded or is already loaded,
// get the JavaScript settings assets. and converts them into a single
// "regular" JavaScript asset.
- $settings_needed = in_array('core/drupalSettings', $this->getLibrariesToLoad()) || in_array('core/drupalSettings', $this->getAlreadyLoadedLibrariesWithDependencies());
- $settings_have_changed = count($this->getLibrariesToLoad()) > 0 || !empty($this->settings);
+ $libraries_to_load = $this->getLibrariesToLoad($assets);
+ $settings_needed = in_array('core/drupalSettings', $libraries_to_load) || in_array('core/drupalSettings', $this->libraryDependencyResolver->getLibrariesWithDependencies($assets->getAlreadyLoadedLibraries()));
+ $settings_have_changed = count($libraries_to_load) > 0 || !empty($assets->getSettings());
if ($settings_needed && $settings_have_changed) {
- $settings = $this->getJsSettingsAssets();
+ $settings = $this->getJsSettingsAssets($assets);
if (!empty($settings)) {
// Prepend to the list of JavaScript assets, to render it first.
$settings_as_inline_javascript = [
@@ -328,15 +247,17 @@ public function getJsAssetsForHeader($optimize) {
* setSettings()) and finally invokes hook_js_settings_alter() to allow
* alterations of JavaScript settings by modules and themes.
*
+ * @param \Drupal\Core\Asset\AttachedAssetsInterface $assets
+ * The assets attached to the current response.
* @return array
* A (possibly optimized) collection of JavaScript assets.
*
* @see ::setSettings()
*/
- protected function getJsSettingsAssets() {
+ protected function getJsSettingsAssets(AttachedAssetsInterface $assets) {
$settings = [];
- foreach ($this->getLibrariesToLoad() as $library) {
+ foreach ($this->getLibrariesToLoad($assets) as $library) {
list($extension, $name) = explode('/', $library, 2);
$definition = $this->libraryDiscovery->getLibraryByName($extension, $name);
if (isset($definition['drupalSettings'])) {
@@ -345,11 +266,11 @@ protected function getJsSettingsAssets() {
}
// Attached settings win over settings in libraries.
- $settings = NestedArray::mergeDeepArray([$settings, $this->settings], TRUE);
+ $settings = NestedArray::mergeDeepArray([$settings, $assets->getSettings()], TRUE);
// Allow modules and themes to alter the JavaScript settings.
- $this->moduleHandler->alter('js_settings', $settings);
- $this->themeManager->alter('js_settings', $settings);
+ $this->moduleHandler->alter('js_settings', $settings, $assets);
+ $this->themeManager->alter('js_settings', $settings, $assets);
return $settings;
}
@@ -357,8 +278,8 @@ protected function getJsSettingsAssets() {
/**
* {@inheritdoc}
*/
- public function getJsAssetsForFooter($optimize) {
- $js_assets = $this->getJsAssets();
+ public function getJsAssetsForFooter(AttachedAssetsInterface $assets, $optimize) {
+ $js_assets = $this->getJsAssets($assets);
// Filter out elements of the given scope.
$js_assets_footer = array();
@@ -380,9 +301,12 @@ public function getJsAssetsForFooter($optimize) {
* @see ::getJsAssetsForHeader()
* @see ::getJsAssetsForFooter()
*
+ * @param \Drupal\Core\Asset\AttachedAssetsInterface $assets
+ * The assets attached to the current response.
+ *
* @return array
*/
- protected function getJsAssets() {
+ protected function getJsAssets(AttachedAssetsInterface $assets) {
// Static caching, because this is called twice (for header & footer).
if (isset($this->jsAssets)) {
return $this->jsAssets;
@@ -390,7 +314,7 @@ protected function getJsAssets() {
$javascript = [];
- foreach ($this->getLibrariesToLoad() as $library) {
+ foreach ($this->getLibrariesToLoad($assets) as $library) {
list($extension, $name) = explode('/', $library, 2);
$definition = $this->libraryDiscovery->getLibraryByName($extension, $name);
if (isset($definition['js'])) {
@@ -422,8 +346,8 @@ protected function getJsAssets() {
}
// Allow modules and themes to alter the JavaScript assets.
- \Drupal::moduleHandler()->alter('js', $javascript);
- \Drupal::theme()->alter('js', $javascript);
+ $this->moduleHandler->alter('js', $javascript, $assets);
+ $this->themeManager->alter('js', $javascript, $assets);
// Sort JavaScript assets, so that they appear in the correct order.
uasort($javascript, 'static::sort');
diff --git a/core/lib/Drupal/Core/Asset/AssetResolverInterface.php b/core/lib/Drupal/Core/Asset/AssetResolverInterface.php
index 02fd938..a3f9d29 100644
--- a/core/lib/Drupal/Core/Asset/AssetResolverInterface.php
+++ b/core/lib/Drupal/Core/Asset/AssetResolverInterface.php
@@ -9,81 +9,19 @@
/**
* Resolves asset libraries into concrete CSS and JavaScript assets.
*
- * Given an ordered list of asset libraries (to be loaded for the current
- * response), the asset resolver can resolve those asset libraries into a list of
- * concrete CSS and JavaScript assets.
+ * Given an attached assets collection (to be loaded for the current response),
+ * the asset resolver can resolve those asset libraries into a list of concrete
+ * CSS and JavaScript assets.
*
* In other words: this allows developers to translate Drupal's asset
* abstraction (asset libraries) into concrete assets.
*
- * Optionally, a set of asset libraries that the client already has loaded can
- * be specified, in which case the asset resolver will figure out which concrete
- * CSS and JavaScript assets the client already has, to prevent loading them
- * again.
- *
+ * @see \Drupal\Core\Asset\AttachedAssetsInterface
* @see \Drupal\Core\Asset\LibraryDependencyResolverInterface
*/
interface AssetResolverInterface {
/**
- * Sets the asset libraries attached to the current response.
- *
- * @param string[] $libraries
- * A list of libraries, in the order they should be loaded.
- *
- * @return $this
- */
- public function setLibraries(array $libraries);
-
- /**
- * Returns the asset libraries attached to the current response.
- *
- * @return string[]
- */
- public function getLibraries();
-
- /**
- * Returns the libraries attached to the current response, with dependencies.
- *
- * @return string[]
- */
- public function getLibrariesWithDependencies();
-
- /**
- * Sets the asset libraries that the current request marked as already loaded.
- *
- * @param string[] $libraries
- * The set of already loaded libraries.
- *
- * @return $this
- */
- public function setAlreadyLoadedLibraries(array $libraries);
-
- /**
- * Returns the set of already loaded asset libraries.
- *
- * @return string[]
- */
- public function getAlreadyLoadedLibraries();
-
- /**
- * Returns the set of already loaded asset libraries, with dependencies.
- *
- * @return string[]
- */
- public function getAlreadyLoadedLibrariesWithDependencies();
-
- /**
- * Sets the JavaScript settings that are attached to the current response.
- *
- * @param array $settings
- * The needed JavaScript settings.
- *
- * @return $this
- */
- public function setSettings(array $settings);
-
- /**
* Returns the CSS assets for the current response's libraries.
*
* It loads the CSS in order, with 'module' first, then 'theme' afterwards.
@@ -97,16 +35,16 @@ public function setSettings(array $settings);
*
* Also invokes hook_css_alter(), to allow CSS assets to be altered.
*
+ * @param \Drupal\Core\Asset\AttachedAssetsInterface $assets
+ * The assets attached to the current response.
* @param bool $optimize
* Whether to apply the CSS asset collection optimizer, to return an
* optimized CSS asset collection rather than an unoptimized one.
*
* @return array
* A (possibly optimized) collection of CSS assets.
- *
- * @see ::getLibrariesToLoad()
*/
- public function getCssAssets($optimize);
+ public function getCssAssets(AttachedAssetsInterface $assets, $optimize);
/**
* Returns the header JavaScript assets for the current response's libraries.
@@ -122,6 +60,8 @@ public function getCssAssets($optimize);
* the $javascript array, deriving from drupal_js_defaults(). See
* locale_js_alter() for an example of this.
*
+ * @param \Drupal\Core\Asset\AttachedAssetsInterface $assets
+ * The assets attached to the current response.
* @param bool $optimize
* Whether to apply the JavaScript asset collection optimizer, to return an
* optimized JavaScript asset collection rather than an unoptimized one.
@@ -129,11 +69,13 @@ public function getCssAssets($optimize);
* @return array
* A (possibly optimized) collection of JavaScript assets.
*/
- public function getJsAssetsForHeader($optimize);
+ public function getJsAssetsForHeader(AttachedAssetsInterface $assets, $optimize);
/**
* Returns the footer JavaScript assets for the current response's libraries.
*
+ * @param \Drupal\Core\Asset\AttachedAssetsInterface $assets
+ * The assets attached to the current response.
* @param bool $optimize
* Whether to apply the JavaScript asset collection optimizer, to return an
* optimized JavaScript asset collection rather than an unoptimized one.
@@ -143,11 +85,6 @@ public function getJsAssetsForHeader($optimize);
*
* @see ::getJsAssetsForHeader()
*/
- public function getJsAssetsForFooter($optimize);
-
- /**
- * Resets all internal state.
- */
- public function reset();
+ public function getJsAssetsForFooter(AttachedAssetsInterface $assets, $optimize);
}
diff --git a/core/lib/Drupal/Core/Asset/AttachedAssets.php b/core/lib/Drupal/Core/Asset/AttachedAssets.php
new file mode 100644
index 0000000..7562f7c
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/AttachedAssets.php
@@ -0,0 +1,95 @@
+setLibraries($render_array['#attached']['library']);
+ }
+ if (isset($render_array['#attached']['drupalSettings'])) {
+ $assets->setSettings($render_array['#attached']['drupalSettings']);
+ }
+ return $assets;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setLibraries(array $libraries) {
+ $this->libraries = array_unique($libraries);
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLibraries() {
+ return $this->libraries;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setSettings(array $settings) {
+ $this->settings = $settings;
+ return $this;
+ }
+
+ public function getSettings() {
+ return $this->settings;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAlreadyLoadedLibraries() {
+ return $this->alreadyLoadedLibraries;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setAlreadyLoadedLibraries(array $libraries) {
+ $this->alreadyLoadedLibraries = $libraries;
+ return $this;
+ }
+
+}
diff --git a/core/lib/Drupal/Core/Asset/AttachedAssetsInterface.php b/core/lib/Drupal/Core/Asset/AttachedAssetsInterface.php
new file mode 100644
index 0000000..338e8b4
--- /dev/null
+++ b/core/lib/Drupal/Core/Asset/AttachedAssetsInterface.php
@@ -0,0 +1,85 @@
+getCurrentLanguage();
$settings['jquery']['ui']['datepicker']['isRTL'] = $language_interface->getDirection() == LanguageInterface::DIRECTION_RTL;
diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module
index 7c0c34f..59173cb 100644
--- a/core/modules/simpletest/simpletest.module
+++ b/core/modules/simpletest/simpletest.module
@@ -1,5 +1,6 @@
'test'), TRUE);
$build['#attached']['library'][] = 'ajax_test/order-css-command';
- $asset_resolver->setLibraries($build['#attached']['library']);
- $css_render_array = $css_collection_renderer->render($asset_resolver->getCssAssets(FALSE));
+ $assets = AttachedAssets::createFromRenderArray($build);
+ $css_render_array = $css_collection_renderer->render($asset_resolver->getCssAssets($assets, FALSE));
$expected_commands[1] = new AddCssCommand($renderer->render($css_render_array));
$build['#attached']['library'][] = 'ajax_test/order-js-command';
- $asset_resolver->setLibraries($build['#attached']['library']);
- $js_header_render_array = $js_collection_renderer->render($asset_resolver->getJsAssetsForHeader(FALSE));
- $js_footer_render_array = $js_collection_renderer->render($asset_resolver->getJsAssetsForFooter(FALSE));
+ $assets = AttachedAssets::createFromRenderArray($build);
+ $js_header_render_array = $js_collection_renderer->render($asset_resolver->getJsAssetsForHeader($assets, FALSE));
+ $js_footer_render_array = $js_collection_renderer->render($asset_resolver->getJsAssetsForFooter($assets, FALSE));
$expected_commands[2] = new PrependCommand('head', $renderer->render($js_header_render_array));
$expected_commands[3] = new AppendCommand('body', $renderer->render($js_footer_render_array));
$expected_commands[4] = new HtmlCommand('body', 'Hello, world!');
@@ -116,14 +117,15 @@ public function testLazyLoad() {
$this->assertTrue(!in_array($expected['library_2'], $original_libraries), format_string('Page originally lacks the %library library, as expected.', array('%library' => $expected['library_2'])));
// Calculate the expected CSS and JS.
- $asset_resolver->setLibraries([$expected['library_1']])
+ $assets = new AttachedAssets();
+ $assets->setLibraries([$expected['library_1']])
->setAlreadyLoadedLibraries($original_libraries);
- $css_render_array = $css_collection_renderer->render($asset_resolver->getCssAssets(FALSE));
+ $css_render_array = $css_collection_renderer->render($asset_resolver->getCssAssets($assets, FALSE));
$expected_css_html = $renderer->render($css_render_array);
- $asset_resolver->setLibraries([$expected['library_2']])
+ $assets->setLibraries([$expected['library_2']])
->setAlreadyLoadedLibraries($original_libraries);
- $js_assets = $asset_resolver->getJsAssetsForHeader(FALSE);
+ $js_assets = $asset_resolver->getJsAssetsForHeader($assets, FALSE);
unset($js_assets['drupalSettings']);
$js_render_array = $js_collection_renderer->render($js_assets);
$expected_js_html = $renderer->render($js_render_array);
diff --git a/core/modules/system/src/Tests/Common/AttachedAssetsTest.php b/core/modules/system/src/Tests/Common/AttachedAssetsTest.php
index 7f4f694..ad492ab 100644
--- a/core/modules/system/src/Tests/Common/AttachedAssetsTest.php
+++ b/core/modules/system/src/Tests/Common/AttachedAssetsTest.php
@@ -10,6 +10,7 @@
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\Crypt;
+use Drupal\Core\Asset\AttachedAssets;
use Drupal\simpletest\KernelTestBase;
/**
@@ -60,9 +61,10 @@ protected function setUp() {
* Tests that default CSS and JavaScript is empty.
*/
function testDefault() {
- $this->assertEqual(array(), $this->assetResolver->getCssAssets(FALSE), 'Default CSS is empty.');
- $this->assertEqual(array(), $this->assetResolver->getJsAssetsForHeader(FALSE), 'Default header JavaScript is empty.');
- $this->assertEqual(array(), $this->assetResolver->getJsAssetsForFooter(FALSE), 'Default footer JavaScript is empty.');
+ $assets = new AttachedAssets();
+ $this->assertEqual(array(), $this->assetResolver->getCssAssets($assets, FALSE), 'Default CSS is empty.');
+ $this->assertEqual(array(), $this->assetResolver->getJsAssetsForHeader($assets, FALSE), 'Default header JavaScript is empty.');
+ $this->assertEqual(array(), $this->assetResolver->getJsAssetsForFooter($assets, FALSE), 'Default footer JavaScript is empty.');
}
/**
@@ -70,9 +72,9 @@ function testDefault() {
*/
function testLibraryUnknown() {
$build['#attached']['library'][] = 'unknown/unknown';
- $this->assetResolver->setLibraries($build['#attached']['library']);
+ $assets = AttachedAssets::createFromRenderArray($build);
- $this->assertIdentical([], $this->assetResolver->getJsAssetsForHeader(FALSE), 'Unknown library was not added to the page.');
+ $this->assertIdentical([], $this->assetResolver->getJsAssetsForHeader($assets, FALSE), 'Unknown library was not added to the page.');
}
/**
@@ -80,10 +82,10 @@ function testLibraryUnknown() {
*/
function testAddFiles() {
$build['#attached']['library'][] = 'common_test/files';
- $this->assetResolver->setLibraries($build['#attached']['library']);
+ $assets = AttachedAssets::createFromRenderArray($build);
- $css = $this->assetResolver->getCssAssets(FALSE);
- $js = $this->assetResolver->getJsAssetsForHeader(FALSE);
+ $css = $this->assetResolver->getCssAssets($assets, FALSE);
+ $js = $this->assetResolver->getJsAssetsForHeader($assets, FALSE);
$this->assertTrue(array_key_exists('bar.css', $css), 'CSS files are correctly added.');
$this->assertTrue(array_key_exists('core/modules/system/tests/modules/common_test/foo.js', $js), 'JavaScript files are correctly added.');
@@ -102,13 +104,13 @@ function testAddFiles() {
function testAddJsSettings() {
// Add a file in order to test default settings.
$build['#attached']['library'][] = 'core/drupalSettings';
- $this->assetResolver->setLibraries($build['#attached']['library']);
+ $assets = AttachedAssets::createFromRenderArray($build);
- $javascript = $this->assetResolver->getJsAssetsForHeader(FALSE);
+ $javascript = $this->assetResolver->getJsAssetsForHeader($assets, FALSE);
$this->assertTrue(array_key_exists('currentPath', $javascript['drupalSettings']['data']['path']), 'The current path JavaScript setting is set correctly.');
- $this->assetResolver->setSettings(['drupal' => 'rocks', 'dries' => 280342800]);
- $javascript = $this->assetResolver->getJsAssetsForHeader(FALSE);
+ $assets->setSettings(['drupal' => 'rocks', 'dries' => 280342800]);
+ $javascript = $this->assetResolver->getJsAssetsForHeader($assets, FALSE);
$this->assertEqual(280342800, $javascript['drupalSettings']['data']['dries'], 'JavaScript setting is set correctly.');
$this->assertEqual('rocks', $javascript['drupalSettings']['data']['drupal'], 'The other JavaScript setting is set correctly.');
}
@@ -118,10 +120,10 @@ function testAddJsSettings() {
*/
function testAddExternalFiles() {
$build['#attached']['library'][] = 'common_test/external';
- $this->assetResolver->setLibraries($build['#attached']['library']);
+ $assets = AttachedAssets::createFromRenderArray($build);
- $css = $this->assetResolver->getCssAssets(FALSE);
- $js = $this->assetResolver->getJsAssetsForHeader(FALSE);
+ $css = $this->assetResolver->getCssAssets($assets, FALSE);
+ $js = $this->assetResolver->getJsAssetsForHeader($assets, FALSE);
$this->assertTrue(array_key_exists('http://example.com/stylesheet.css', $css), 'External CSS files are correctly added.');
$this->assertTrue(array_key_exists('http://example.com/script.js', $js), 'External JavaScript files are correctly added.');
@@ -138,9 +140,9 @@ function testAddExternalFiles() {
*/
function testAttributes() {
$build['#attached']['library'][] = 'common_test/js-attributes';
- $this->assetResolver->setLibraries($build['#attached']['library']);
+ $assets = AttachedAssets::createFromRenderArray($build);
- $js = $this->assetResolver->getJsAssetsForHeader(FALSE);
+ $js = $this->assetResolver->getJsAssetsForHeader($assets, FALSE);
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->render($js_render_array);
$expected_1 = '';
@@ -154,9 +156,9 @@ function testAttributes() {
*/
function testAggregatedAttributes() {
$build['#attached']['library'][] = 'common_test/js-attributes';
- $this->assetResolver->setLibraries($build['#attached']['library']);
+ $assets = AttachedAssets::createFromRenderArray($build);
- $js = $this->assetResolver->getJsAssetsForHeader(TRUE);
+ $js = $this->assetResolver->getJsAssetsForHeader($assets, TRUE);
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->render($js_render_array);
$expected_1 = '';
@@ -173,10 +175,9 @@ function testHeaderSetting() {
$build['#attached']['library'][] = 'core/drupalSettings';
// Nonsensical value to verify if it's possible to override path settings.
$build['#attached']['drupalSettings']['path']['pathPrefix'] = 'yarhar';
- $this->assetResolver->setLibraries($build['#attached']['library'])
- ->setSettings($build['#attached']['drupalSettings']);
+ $assets = AttachedAssets::createFromRenderArray($build);
- $js = $this->assetResolver->getJsAssetsForHeader(FALSE);
+ $js = $this->assetResolver->getJsAssetsForHeader($assets, FALSE);
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->render($js_render_array);
@@ -209,9 +210,9 @@ function testHeaderSetting() {
*/
function testFooterHTML() {
$build['#attached']['library'][] = 'common_test/js-footer';
- $this->assetResolver->setLibraries($build['#attached']['library']);
+ $assets = AttachedAssets::createFromRenderArray($build);
- $js = $this->assetResolver->getJsAssetsForFooter(FALSE);
+ $js = $this->assetResolver->getJsAssetsForFooter($assets, FALSE);
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->render($js_render_array);
$query_string = $this->container->get('state')->get('system.css_js_query_string') ?: '0';
@@ -223,9 +224,9 @@ function testFooterHTML() {
*/
function testNoCache() {
$build['#attached']['library'][] = 'common_test/no-cache';
- $this->assetResolver->setLibraries($build['#attached']['library']);
+ $assets = AttachedAssets::createFromRenderArray($build);
- $js = $this->assetResolver->getJsAssetsForHeader(FALSE);
+ $js = $this->assetResolver->getJsAssetsForHeader($assets, FALSE);
$this->assertFalse($js['core/modules/system/tests/modules/common_test/nocache.js']['preprocess'], 'Setting cache to FALSE sets preprocess to FALSE when adding JavaScript.');
}
@@ -238,9 +239,9 @@ function testBrowserConditionalComments() {
$default_query_string = $this->container->get('state')->get('system.css_js_query_string') ?: '0';
$build['#attached']['library'][] = 'common_test/browsers';
- $this->assetResolver->setLibraries($build['#attached']['library']);
+ $assets = AttachedAssets::createFromRenderArray($build);
- $js = $this->assetResolver->getJsAssetsForHeader(FALSE);
+ $js = $this->assetResolver->getJsAssetsForHeader($assets, FALSE);
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->render($js_render_array);
$expected_1 = "";
@@ -256,9 +257,9 @@ function testBrowserConditionalComments() {
function testVersionQueryString() {
$build['#attached']['library'][] = 'core/backbone';
$build['#attached']['library'][] = 'core/domready';
- $this->assetResolver->setLibraries($build['#attached']['library']);
+ $assets = AttachedAssets::createFromRenderArray($build);
- $js = $this->assetResolver->getJsAssetsForHeader(FALSE);
+ $js = $this->assetResolver->getJsAssetsForHeader($assets, FALSE);
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->render($js_render_array);
$this->assertTrue(strpos($rendered_js, 'core/assets/vendor/backbone/backbone-min.js?v=1.1.2') > 0 && strpos($rendered_js, 'core/assets/vendor/domready/ready.min.js?v=1.0.7') > 0 , 'JavaScript version identifiers correctly appended to URLs');
@@ -269,7 +270,7 @@ function testVersionQueryString() {
*/
function testRenderOrder() {
$build['#attached']['library'][] = 'common_test/order';
- $this->assetResolver->setLibraries($build['#attached']['library']);
+ $assets = AttachedAssets::createFromRenderArray($build);
// Construct the expected result from the regex.
$expected_order_js = [
@@ -286,7 +287,7 @@ function testRenderOrder() {
];
// Retrieve the rendered JavaScript and test against the regex.
- $js = $this->assetResolver->getJsAssetsForHeader(FALSE);
+ $js = $this->assetResolver->getJsAssetsForHeader($assets, FALSE);
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->render($js_render_array);
$matches = array();
@@ -328,7 +329,7 @@ function testRenderOrder() {
];
// Retrieve the rendered CSS and test against the regex.
- $css = $this->assetResolver->getCssAssets(FALSE);
+ $css = $this->assetResolver->getCssAssets($assets, FALSE);
$css_render_array = \Drupal::service('asset.css.collection_renderer')->render($css);
$rendered_css = $this->renderer->render($css_render_array);
$matches = array();
@@ -349,9 +350,9 @@ function testRenderDifferentWeight() {
// still make itself appear first by defining a lower weight.
$build['#attached']['library'][] = 'core/jquery';
$build['#attached']['library'][] = 'common_test/weight';
- $this->assetResolver->setLibraries($build['#attached']['library']);
+ $assets = AttachedAssets::createFromRenderArray($build);
- $js = $this->assetResolver->getJsAssetsForHeader(FALSE);
+ $js = $this->assetResolver->getJsAssetsForHeader($assets, FALSE);
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->render($js_render_array);
$this->assertTrue(strpos($rendered_js, 'lighter.css') < strpos($rendered_js, 'first.js'), 'Lighter CSS assets are rendered first.');
@@ -368,12 +369,12 @@ function testAlter() {
// Add both tableselect.js and simpletest.js.
$build['#attached']['library'][] = 'core/drupal.tableselect';
$build['#attached']['library'][] = 'simpletest/drupal.simpletest';
- $this->assetResolver->setLibraries($build['#attached']['library']);
+ $assets = AttachedAssets::createFromRenderArray($build);
// Render the JavaScript, testing if simpletest.js was altered to be before
// tableselect.js. See simpletest_js_alter() to see where this alteration
// takes place.
- $js = $this->assetResolver->getJsAssetsForHeader(FALSE);
+ $js = $this->assetResolver->getJsAssetsForHeader($assets, FALSE);
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->render($js_render_array);
$this->assertTrue(strpos($rendered_js, 'simpletest.js') < strpos($rendered_js, 'core/misc/tableselect.js'), 'Altering JavaScript weight through the alter hook.');
@@ -393,8 +394,8 @@ function testLibraryAlter() {
// common_test_library_info_alter() also added a dependency on jQuery Form.
$build['#attached']['library'][] = 'core/jquery.farbtastic';
- $this->assetResolver->setLibraries($build['#attached']['library']);
- $js = $this->assetResolver->getJsAssetsForHeader(FALSE);
+ $assets = AttachedAssets::createFromRenderArray($build);
+ $js = $this->assetResolver->getJsAssetsForHeader($assets, FALSE);
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->render($js_render_array);
$this->assertTrue(strpos($rendered_js, 'core/assets/vendor/jquery-form/jquery.form.js'), 'Altered library dependencies are added to the page.');
@@ -417,10 +418,10 @@ function testLibraryNameConflicts() {
*/
function testAddJsFileWithQueryString() {
$build['#attached']['library'][] = 'common_test/querystring';
- $this->assetResolver->setLibraries($build['#attached']['library']);
+ $assets = AttachedAssets::createFromRenderArray($build);
- $css = $this->assetResolver->getCssAssets(FALSE);
- $js = $this->assetResolver->getJsAssetsForHeader(FALSE);
+ $css = $this->assetResolver->getCssAssets($assets, FALSE);
+ $js = $this->assetResolver->getJsAssetsForHeader($assets, FALSE);
$this->assertTrue(array_key_exists('querystring.css?arg1=value1&arg2=value2', $css), 'CSS file with query string is correctly added.');
$this->assertTrue(array_key_exists('core/modules/system/tests/modules/common_test/querystring.js?arg1=value1&arg2=value2', $js), 'JavaScript file with query string is correctly added.');
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 27e2f3e..d33c466 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -6,6 +6,7 @@
*/
use Drupal\Component\Utility\UrlHelper;
+use Drupal\Core\Asset\AttachedAssetsInterface;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Extension\Extension;
use Drupal\Core\Extension\ExtensionDiscovery;
@@ -621,7 +622,7 @@ function system_page_attachments(array &$page) {
*
* Sets values for the core/drupalSettings and core/drupal.ajax libraries.
*/
-function system_js_settings_alter(&$settings) {
+function system_js_settings_alter(&$settings, AttachedAssetsInterface $assets) {
// 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().
@@ -666,9 +667,9 @@ function system_js_settings_alter(&$settings) {
// - core/drupal.ajax already has been loaded and hence this is an AJAX
// Response in which we must send the list of extra asset libraries that are
// being added in this AJAX Response.
- /** @var \Drupal\Core\Asset\AssetResolverInterface $asset_resolver */
- $asset_resolver = \Drupal::service('asset.resolver');
- if (isset($settings['ajaxPageState']) || in_array('core/drupal.ajax', $asset_resolver->getAlreadyLoadedLibrariesWithDependencies())) {
+ /** @var \Drupal\Core\Asset\LibraryDependencyResolver $library_dependency_resolver */
+ $library_dependency_resolver = \Drupal::service('library.dependency_resolver');
+ if (isset($settings['ajaxPageState']) || in_array('core/drupal.ajax', $library_dependency_resolver->getLibrariesWithDependencies($assets->getAlreadyLoadedLibraries()))) {
// Provide the page with information about the theme that's used, so that
// a later AJAX request can be rendered using the same theme.
// @see \Drupal\Core\Theme\AjaxBasePageNegotiator
@@ -681,11 +682,10 @@ function system_js_settings_alter(&$settings) {
// Provide the page with information about the individual asset libraries
// used, information not otherwise available when aggregation is enabled.
- $library_dependency_resolver = \Drupal::service('library.dependency_resolver');
- $minimal_libraries = $library_dependency_resolver->getMinimalRepresentativeSubset(array_unique(array_merge(
- $asset_resolver->getLibrariesWithDependencies(),
- $asset_resolver->getAlreadyLoadedLibrariesWithDependencies()
- )));
+ $minimal_libraries = $library_dependency_resolver->getMinimalRepresentativeSubset(array_merge(
+ $assets->getLibraries(),
+ $assets->getAlreadyLoadedLibraries()
+ ));
sort($minimal_libraries);
$settings['ajaxPageState']['libraries'] = implode(',', $minimal_libraries);
}
diff --git a/core/modules/system/tests/modules/common_test/common_test.module b/core/modules/system/tests/modules/common_test/common_test.module
index 8dbf98a..b63deb6 100644
--- a/core/modules/system/tests/modules/common_test/common_test.module
+++ b/core/modules/system/tests/modules/common_test/common_test.module
@@ -5,6 +5,8 @@
* Helper module for the Common tests.
*/
+use \Drupal\Core\Asset\AttachedAssetsInterface;
+
/**
* Applies #printed to an element to help test #pre_render.
*/
@@ -324,7 +326,7 @@ function common_test_page_attachments_alter(array &$page) {
*
* @see \Drupal\system\Tests\Common\JavaScriptTest::testHeaderSetting()
*/
-function common_test_js_settings_alter(&$settings) {
+function common_test_js_settings_alter(&$settings, AttachedAssetsInterface $assets) {
// Modify an existing setting.
if (array_key_exists('pluralDelimiter', $settings['locale'])) {
$settings['locale']['pluralDelimiter'] = '☃';
diff --git a/core/modules/system/theme.api.php b/core/modules/system/theme.api.php
index 9ee2ab1..337b5df 100644
--- a/core/modules/system/theme.api.php
+++ b/core/modules/system/theme.api.php
@@ -711,11 +711,13 @@ function hook_element_info_alter(array &$types) {
*
* @param $javascript
* An array of all JavaScript being presented on the page.
+ * @param \Drupal\Core\Asset\AttachedAssetsInterface $assets
+ * The assets attached to the current response.
*
* @see drupal_js_defaults()
* @see \Drupal\Core\Asset\AssetResolver
*/
-function hook_js_alter(&$javascript) {
+function hook_js_alter(&$javascript, \Drupal\Core\Asset\AttachedAssetsInterface $assets) {
// Swap out jQuery to use an updated version of the library.
$javascript['core/assets/vendor/jquery/jquery.min.js']['data'] = drupal_get_path('module', 'jquery_update') . '/jquery.js';
}
@@ -726,10 +728,12 @@ function hook_js_alter(&$javascript) {
* @param array &$settings
* An array of all JavaScript settings (drupalSettings) being presented on the
* page.
+ * @param \Drupal\Core\Asset\AttachedAssetsInterface $assets
+ * The assets attached to the current response.
*
* @see \Drupal\Core\Asset\AssetResolver
*/
-function hook_js_settings_alter(array &$settings) {
+function hook_js_settings_alter(array &$settings, \Drupal\Core\Asset\AttachedAssetsInterface $assets) {
// Add settings.
$settings['user']['uid'] = \Drupal::currentUser();
@@ -789,10 +793,12 @@ function hook_library_info_alter(&$libraries, $module) {
*
* @param $css
* An array of all CSS items (files and inline CSS) being requested on the page.
+ * @param \Drupal\Core\Asset\AttachedAssetsInterface $assets
+ * The assets attached to the current response.
*
* @see Drupal\Core\Asset\LibraryResolverInterface::getCssAssets()
*/
-function hook_css_alter(&$css) {
+function hook_css_alter(&$css, \Drupal\Core\Asset\AttachedAssetsInterface $assets) {
// Remove defaults.css file.
unset($css[drupal_get_path('module', 'system') . '/defaults.css']);
}
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index a251fd7..e6db06e 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -3,6 +3,7 @@
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Asset\AttachedAssetsInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
@@ -110,7 +111,7 @@ function user_theme() {
/**
* Implements hook_js_settings_alter().
*/
-function user_js_settings_alter(&$settings) {
+function user_js_settings_alter(&$settings, AttachedAssetsInterface $assets) {
// Provide the user ID in drupalSettings to allow JavaScript code to customize
// the experience for the end user, rather than the server side, which would
// break the render cache.