Skip to content
Snippets Groups Projects
Commit b95d2c83 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #2497667 by almaudoh, Wim Leers, Cottser, Fabianx, jaxxed: Add...

Issue #2497667 by almaudoh, Wim Leers, Cottser, Fabianx, jaxxed: Add libraries-extend to themes' *.info.yml
parent bbc98524
No related branches found
No related tags found
No related merge requests found
Showing
with 191 additions and 2 deletions
<?php
/**
* @file
* Contains \Drupal\Core\Asset\Exception\InvalidLibrariesExtendSpecificationException.
*/
namespace Drupal\Core\Asset\Exception;
/**
* Defines a custom exception for an invalid libraries-extend specification.
*/
class InvalidLibrariesExtendSpecificationException extends \RuntimeException {
}
......@@ -7,6 +7,8 @@
namespace Drupal\Core\Asset;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Asset\Exception\InvalidLibrariesExtendSpecificationException;
use Drupal\Core\Asset\Exception\InvalidLibrariesOverrideSpecificationException;
use Drupal\Core\Cache\CacheCollector;
use Drupal\Core\Cache\CacheBackendInterface;
......@@ -124,8 +126,50 @@ protected function getLibraryDefinitions($extension) {
}
}
}
else {
// If libraries are not overridden, then apply libraries-extend.
$libraries[$name] = $this->applyLibrariesExtend($extension, $name, $definition);
}
}
return $libraries;
}
/**
* Applies the libraries-extend specified by the active theme.
*
* This extends the library definitions with the those specified by the
* libraries-extend specifications for the active theme.
*
* @param string $extension
* The name of the extension for which library definitions will be extended.
* @param string $library_name
* The name of the library whose definitions is to be extended.
* @param $library_definition
* The library definition to be extended.
*
* @return array
* The library definition extended as specified by libraries-extend.
*
* @throws \Drupal\Core\Asset\Exception\InvalidLibrariesExtendSpecificationException
*/
protected function applyLibrariesExtend($extension, $library_name, $library_definition) {
$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 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);
if (isset($new_libraries[$new_library_name])) {
$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));
}
}
}
return $library_definition;
}
}
......@@ -104,6 +104,7 @@ public function __construct(array $values) {
'base_themes' => [],
'regions' => [],
'libraries_override' => [],
'libraries_extend' => [],
];
$this->name = $values['name'];
......@@ -116,6 +117,7 @@ public function __construct(array $values) {
$this->baseThemes = $values['base_themes'];
$this->regions = $values['regions'];
$this->librariesOverride = $values['libraries_override'];
$this->librariesExtend = $values['libraries_extend'];
}
/**
......@@ -219,4 +221,14 @@ public function getLibrariesOverride() {
return $this->librariesOverride;
}
/**
* Returns the libraries extended by the active theme.
*
* @return array
* The list of libraries-extend definitions.
*/
public function getLibrariesExtend() {
return $this->librariesExtend;
}
}
......@@ -185,6 +185,35 @@ public function getActiveTheme(Extension $theme, array $base_themes = []) {
}
}
// Get libraries extensions declared by base themes.
foreach ($base_themes as $base) {
if (!empty($base->info['libraries-extend'])) {
foreach ($base->info['libraries-extend'] as $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 extensions declared by this theme.
if (!empty($theme->info['libraries-extend'])) {
foreach ($theme->info['libraries-extend'] as $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;
}
}
}
// Do basically the same as the above for libraries
$values['libraries'] = array();
......
......@@ -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;
......@@ -158,6 +159,54 @@ public function testBaseThemeLibrariesOverrideInSubTheme() {
$this->assertAssetInLibrary('core/modules/system/tests/themes/test_basetheme/css/farbtastic.css', 'core', 'jquery.farbtastic', 'css');
}
/**
* Tests libraries-extend.
*/
public function testLibrariesExtend() {
// Activate classy themes and verify the libraries are not extended.
$this->activateTheme('classy');
$this->assertNoAssetInLibrary('core/modules/system/tests/themes/test_theme_libraries_extend/css/extend_1.css', 'classy', 'book-navigation', 'css');
$this->assertNoAssetInLibrary('core/modules/system/tests/themes/test_theme_libraries_extend/js/extend_1.js', 'classy', 'book-navigation', 'js');
$this->assertNoAssetInLibrary('core/modules/system/tests/themes/test_theme_libraries_extend/css/extend_2.css', 'classy', 'book-navigation', 'css');
// Activate the theme that extends the book-navigation library in classy.
$this->activateTheme('test_theme_libraries_extend');
$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.');
}
}
/**
* Activates a specified theme.
*
......@@ -178,6 +227,9 @@ protected function activateTheme($theme_name) {
$theme_manager->setActiveTheme($theme_initializer->getActiveThemeByName($theme_name));
$this->libraryDiscovery->clearCachedDefinitions();
// Assert message.
$this->pass(sprintf('Activated theme "%s"', $theme_name));
}
/**
......
......@@ -15,3 +15,7 @@ libraries-override:
css:
component:
assets/vendor/farbtastic/farbtastic.css: css/farbtastic.css
libraries-extend:
classy/base:
- test_basetheme/global-styling
......@@ -5,3 +5,4 @@ global-styling:
base-add.css: {}
base-add.sub-remove.css: {}
samename.css: {}
css/base-libraries-extend.css: {}
......@@ -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
......@@ -4,3 +4,4 @@ global-styling:
base:
css/sub-add.css: {}
css/samename.css: {}
css/sub-libraries-extend.css: {}
name: 'Test theme libraries-extend'
type: theme
description: 'Test Theme with libraries-extend'
version: VERSION
base theme: classy
core: 8.x
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'
extend_one:
css:
theme:
css/extend_1.css: { }
js:
js/extend_1.js: { }
extend_two:
css:
theme:
css/extend_2.css: { }
......@@ -94,7 +94,7 @@ public function testResolveCacheMiss() {
$this->activeTheme = $this->getMockBuilder('Drupal\Core\Theme\ActiveTheme')
->disableOriginalConstructor()
->getMock();
$this->themeManager->expects($this->once())
$this->themeManager->expects($this->exactly(3))
->method('getActiveTheme')
->willReturn($this->activeTheme);
$this->activeTheme->expects($this->once())
......@@ -120,7 +120,7 @@ public function testDestruct() {
$this->activeTheme = $this->getMockBuilder('Drupal\Core\Theme\ActiveTheme')
->disableOriginalConstructor()
->getMock();
$this->themeManager->expects($this->once())
$this->themeManager->expects($this->exactly(3))
->method('getActiveTheme')
->willReturn($this->activeTheme);
$this->activeTheme->expects($this->once())
......
......@@ -94,6 +94,7 @@ public function testGetRegistryForModule() {
'owner' => 'twig',
'stylesheets_remove' => [],
'libraries_override' => [],
'libraries_extend' => [],
'libraries' => [],
'extension' => '.twig',
'base_themes' => [],
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment