diff --git a/core/lib/Drupal/Core/Asset/LibraryDiscoveryCollector.php b/core/lib/Drupal/Core/Asset/LibraryDiscoveryCollector.php index f7dc640..f0a590a 100644 --- a/core/lib/Drupal/Core/Asset/LibraryDiscoveryCollector.php +++ b/core/lib/Drupal/Core/Asset/LibraryDiscoveryCollector.php @@ -127,7 +127,7 @@ protected function getLibraryDefinitions($extension) { } } else { - // Apply libraries extend. + // If libraries are not overridden, then apply libraries extend. $libraries[$name] = $this->applyLibrariesExtend($extension, $name, $definition); } } @@ -153,12 +153,12 @@ protected function getLibraryDefinitions($extension) { * @throws \Drupal\Core\Asset\Exception\InvalidLibrariesExtendSpecificationException */ protected function applyLibrariesExtend($extension, $library_name, $library_definition) { - $active_theme = $this->themeManager->getActiveTheme()->getLibrariesExtend(); - if (!empty($active_theme["$extension/$library_name"])) { - foreach ($active_theme["$extension/$library_name"] as $library_extend_name) { + $libraries_extend = $this->themeManager->getActiveTheme()->getLibrariesExtend(); + if (!empty($libraries_extend["$extension/$library_name"])) { + foreach ($libraries_extend["$extension/$library_name"] as $library_extend_name) { if (!is_string($library_extend_name)) { // Only string library names are allowed. - throw new InvalidLibrariesExtendSpecificationException('The libraries-extend specification must be a string.'); + throw new InvalidLibrariesExtendSpecificationException('The libraries-extend specification for each library must be a list of strings.'); } list($new_extension, $new_library_name) = explode('/', $library_extend_name, 2); $new_libraries = $this->get($new_extension); @@ -166,7 +166,7 @@ protected function applyLibrariesExtend($extension, $library_name, $library_defi $library_definition = NestedArray::mergeDeep($library_definition, $new_libraries[$new_library_name]); } else { - throw new InvalidLibrariesExtendSpecificationException(sprintf('The specified library %s does not exist.', $library_extend_name)); + throw new InvalidLibrariesExtendSpecificationException(sprintf('The specified library "%s" does not exist.', $library_extend_name)); } } } diff --git a/core/lib/Drupal/Core/Theme/ThemeInitialization.php b/core/lib/Drupal/Core/Theme/ThemeInitialization.php index e9bae2d..e310777 100644 --- a/core/lib/Drupal/Core/Theme/ThemeInitialization.php +++ b/core/lib/Drupal/Core/Theme/ThemeInitialization.php @@ -189,14 +189,28 @@ public function getActiveTheme(Extension $theme, array $base_themes = []) { foreach ($base_themes as $base) { if (!empty($base->info['libraries-extend'])) { foreach ($base->info['libraries-extend'] as $library => $extend) { - $values['libraries_extend'][$library] = $extend; + if (isset($values['libraries_extend'][$library])) { + // Merge if libraries-extend has already been defined for this + // library. + $values['libraries_extend'][$library] = array_merge($values['libraries_extend'][$library], $extend); + } + else { + $values['libraries_extend'][$library] = $extend; + } } } } // Add libraries extend declared by this theme. if (!empty($theme->info['libraries-extend'])) { foreach ($theme->info['libraries-extend'] as $library => $extend) { - $values['libraries_extend'][$library] = $extend; + if (isset($values['libraries_extend'][$library])) { + // Merge if libraries-extend has already been defined for this + // library. + $values['libraries_extend'][$library] = array_merge($values['libraries_extend'][$library], $extend); + } + else { + $values['libraries_extend'][$library] = $extend; + } } } diff --git a/core/modules/system/src/Tests/Asset/LibraryDiscoveryIntegrationTest.php b/core/modules/system/src/Tests/Asset/LibraryDiscoveryIntegrationTest.php index a535ea8..2de5680 100644 --- a/core/modules/system/src/Tests/Asset/LibraryDiscoveryIntegrationTest.php +++ b/core/modules/system/src/Tests/Asset/LibraryDiscoveryIntegrationTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Asset; +use Drupal\Core\Asset\Exception\InvalidLibrariesExtendSpecificationException; use Drupal\Core\Asset\Exception\InvalidLibrariesOverrideSpecificationException; use Drupal\simpletest\KernelTestBase; @@ -173,6 +174,37 @@ public function testLibrariesExtend() { $this->assertAssetInLibrary('core/modules/system/tests/themes/test_theme_libraries_extend/css/extend_1.css', 'classy', 'book-navigation', 'css'); $this->assertAssetInLibrary('core/modules/system/tests/themes/test_theme_libraries_extend/js/extend_1.js', 'classy', 'book-navigation', 'js'); $this->assertAssetInLibrary('core/modules/system/tests/themes/test_theme_libraries_extend/css/extend_2.css', 'classy', 'book-navigation', 'css'); + + // Activate a sub theme and confirm that it inherits the library assets + // extended in the base theme as well as its own. + $this->assertNoAssetInLibrary('core/modules/system/tests/themes/test_basetheme/css/base-libraries-extend.css', 'classy', 'base', 'css'); + $this->assertNoAssetInLibrary('core/modules/system/tests/themes/test_subtheme/css/sub-libraries-extend.css', 'classy', 'base', 'css'); + $this->activateTheme('test_subtheme'); + $this->assertAssetInLibrary('core/modules/system/tests/themes/test_basetheme/css/base-libraries-extend.css', 'classy', 'base', 'css'); + $this->assertAssetInLibrary('core/modules/system/tests/themes/test_subtheme/css/sub-libraries-extend.css', 'classy', 'base', 'css'); + + // Activate test theme that extends with a non-existent library. An + // exception should be thrown. + $this->activateTheme('test_theme_libraries_extend'); + try { + $this->libraryDiscovery->getLibraryByName('core', 'drupal.dialog'); + $this->fail('Throw Exception when specifying non-existent libraries-extend.'); + } + catch (InvalidLibrariesExtendSpecificationException $e) { + $expected_message = 'The specified library "test_theme_libraries_extend/non_existent_library" does not exist.'; + $this->assertEqual($e->getMessage(), $expected_message, 'Throw Exception when specifying non-existent libraries-extend.'); + } + + // Also, test non-string libraries-extend. An exception should be thrown. + $this->container->get('theme_installer')->install(['test_theme']); + try { + $this->libraryDiscovery->getLibraryByName('test_theme', 'collapse'); + $this->fail('Throw Exception when specifying non-string libraries-extend.'); + } + catch (InvalidLibrariesExtendSpecificationException $e) { + $expected_message = 'The libraries-extend specification for each library must be a list of strings.'; + $this->assertEqual($e->getMessage(), $expected_message, 'Throw Exception when specifying non-string libraries-extend.'); + } } /** diff --git a/core/modules/system/tests/themes/test_basetheme/test_basetheme.info.yml b/core/modules/system/tests/themes/test_basetheme/test_basetheme.info.yml index 3637a0c..7b76ded 100644 --- a/core/modules/system/tests/themes/test_basetheme/test_basetheme.info.yml +++ b/core/modules/system/tests/themes/test_basetheme/test_basetheme.info.yml @@ -15,3 +15,7 @@ libraries-override: css: component: assets/vendor/farbtastic/farbtastic.css: css/farbtastic.css + +libraries-extend: + classy/base: + - test_basetheme/global-styling diff --git a/core/modules/system/tests/themes/test_basetheme/test_basetheme.libraries.yml b/core/modules/system/tests/themes/test_basetheme/test_basetheme.libraries.yml index f7529ea..b3d3406 100644 --- a/core/modules/system/tests/themes/test_basetheme/test_basetheme.libraries.yml +++ b/core/modules/system/tests/themes/test_basetheme/test_basetheme.libraries.yml @@ -5,3 +5,4 @@ global-styling: base-add.css: {} base-add.sub-remove.css: {} samename.css: {} + css/base-libraries-extend.css: {} diff --git a/core/modules/system/tests/themes/test_subtheme/test_subtheme.info.yml b/core/modules/system/tests/themes/test_subtheme/test_subtheme.info.yml index 6883e5a..b217374 100644 --- a/core/modules/system/tests/themes/test_subtheme/test_subtheme.info.yml +++ b/core/modules/system/tests/themes/test_subtheme/test_subtheme.info.yml @@ -9,3 +9,7 @@ libraries: stylesheets-remove: - '@theme_test/css/sub-remove.css' - '@test_basetheme/base-add.sub-remove.css' + +libraries-extend: + classy/base: + - test_subtheme/global-styling diff --git a/core/modules/system/tests/themes/test_subtheme/test_subtheme.libraries.yml b/core/modules/system/tests/themes/test_subtheme/test_subtheme.libraries.yml index 931dffe..1fff390 100644 --- a/core/modules/system/tests/themes/test_subtheme/test_subtheme.libraries.yml +++ b/core/modules/system/tests/themes/test_subtheme/test_subtheme.libraries.yml @@ -4,3 +4,4 @@ global-styling: base: css/sub-add.css: {} css/samename.css: {} + css/sub-libraries-extend.css: {} diff --git a/core/modules/system/tests/themes/test_theme_libraries_extend/test_theme_libraries_extend.info.yml b/core/modules/system/tests/themes/test_theme_libraries_extend/test_theme_libraries_extend.info.yml index f312c89..597a5b0 100644 --- a/core/modules/system/tests/themes/test_theme_libraries_extend/test_theme_libraries_extend.info.yml +++ b/core/modules/system/tests/themes/test_theme_libraries_extend/test_theme_libraries_extend.info.yml @@ -8,3 +8,8 @@ libraries-extend: classy/book-navigation: - test_theme_libraries_extend/extend_one - test_theme_libraries_extend/extend_two + core/drupal.dialog: + - test_theme_libraries_extend/non_existent_library + test_theme/collapse: + - not_a_string: + expected: 'an exception'