diff --git a/core/core.services.yml b/core/core.services.yml index 6127c8f..3364e78 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1192,7 +1192,7 @@ services: - [setThemeRegistry, ['@theme.registry']] theme.initialization: class: Drupal\Core\Theme\ThemeInitialization - arguments: ['@app.root', '@theme_handler', '@state'] + arguments: ['@app.root', '@theme_handler', '@state', '@module_handler'] theme.registry: class: Drupal\Core\Theme\Registry arguments: ['@app.root', '@cache.default', '@lock', '@module_handler', '@theme_handler', '@theme.initialization'] diff --git a/core/lib/Drupal/Core/Asset/AssetResolver.php b/core/lib/Drupal/Core/Asset/AssetResolver.php index e544dee..bc8f69f 100644 --- a/core/lib/Drupal/Core/Asset/AssetResolver.php +++ b/core/lib/Drupal/Core/Asset/AssetResolver.php @@ -124,23 +124,8 @@ public function getCssAssets(AttachedAssetsInterface $assets, $optimize) { // order. $options['weight'] += count($css) / 1000; - // Add the data to the CSS array depending on the type. - switch ($options['type']) { - case 'file': - // Local CSS files are keyed by basename; if a file with the same - // basename is added more than once, it gets overridden. - // By default, take over the filename as basename. - if (!isset($options['basename'])) { - $options['basename'] = \Drupal::service('file_system')->basename($options['data']); - } - $css[$options['basename']] = $options; - break; - - default: - // External files are keyed by their full URI, so the same CSS - // file is not added twice. - $css[$options['data']] = $options; - } + // CSS files are being keyed by the full path. + $css[$options['data']] = $options; } } } @@ -152,22 +137,14 @@ public function getCssAssets(AttachedAssetsInterface $assets, $optimize) { // Sort CSS items, so that they appear in the correct order. uasort($css, 'static::sort'); - // Allow themes to remove CSS files by basename. + // Allow themes to remove CSS files by CSS files full path and file name. if ($stylesheet_remove = $theme_info->getStyleSheetsRemove()) { foreach ($css as $key => $options) { - if (isset($options['basename']) && isset($stylesheet_remove[$options['basename']])) { + if (isset($stylesheet_remove[$key])) { unset($css[$key]); } } } - // Allow themes to conditionally override CSS files by basename. - if ($stylesheet_override = $theme_info->getStyleSheetsOverride()) { - foreach ($css as $key => $options) { - if (isset($options['basename']) && isset($stylesheet_override[$options['basename']])) { - $css[$key]['data'] = $stylesheet_override[$options['basename']]; - } - } - } if ($optimize) { $css = \Drupal::service('asset.css.collection_optimizer')->optimize($css); diff --git a/core/lib/Drupal/Core/Theme/ActiveTheme.php b/core/lib/Drupal/Core/Theme/ActiveTheme.php index e1d9a96..aace6f9 100644 --- a/core/lib/Drupal/Core/Theme/ActiveTheme.php +++ b/core/lib/Drupal/Core/Theme/ActiveTheme.php @@ -67,13 +67,6 @@ class ActiveTheme { protected $styleSheetsRemove; /** - * The stylesheets which are overridden by the theme. - * - * @var array - */ - protected $styleSheetsOverride; - - /** * The libraries provided by the theme. * * @var array @@ -92,17 +85,16 @@ public function __construct(array $values) { 'engine' => 'twig', 'owner' => 'twig', 'stylesheets_remove' => [], - 'stylesheets_override' => [], 'libraries' => [], 'extension' => 'html.twig', 'base_themes' => [], ]; + $this->name = $values['name']; $this->path = $values['path']; $this->engine = $values['engine']; $this->owner = $values['owner']; $this->styleSheetsRemove = $values['stylesheets_remove']; - $this->styleSheetsOverride = $values['stylesheets_override']; $this->libraries = $values['libraries']; $this->extension = $values['extension']; $this->baseThemes = $values['base_themes']; @@ -165,15 +157,6 @@ public function getLibraries() { } /** - * Returns the overridden stylesheets by the theme. - * - * @return mixed - */ - public function getStyleSheetsOverride() { - return $this->styleSheetsOverride; - } - - /** * Returns the removed stylesheets by the theme. * * @return mixed diff --git a/core/lib/Drupal/Core/Theme/ThemeInitialization.php b/core/lib/Drupal/Core/Theme/ThemeInitialization.php index 29c8205..40f6902 100644 --- a/core/lib/Drupal/Core/Theme/ThemeInitialization.php +++ b/core/lib/Drupal/Core/Theme/ThemeInitialization.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Theme; use Drupal\Core\Extension\Extension; +use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ThemeHandlerInterface; use Drupal\Core\State\StateInterface; @@ -38,6 +39,13 @@ class ThemeInitialization implements ThemeInitializationInterface { protected $root; /** + * The extensions that might be attaching assets. + * + * @var array + */ + protected $extensions; + + /** * Constructs a new ThemeInitialization object. * * @param string $root @@ -47,10 +55,12 @@ class ThemeInitialization implements ThemeInitializationInterface { * @param \Drupal\Core\State\StateInterface $state * The state. */ - public function __construct($root, ThemeHandlerInterface $theme_handler, StateInterface $state) { + public function __construct($root, ThemeHandlerInterface $theme_handler, StateInterface $state, ModuleHandlerInterface $module_handler) { $this->root = $root; $this->themeHandler = $theme_handler; $this->state = $state; + + $this->moduleHandler = $module_handler; } /** @@ -101,6 +111,7 @@ public function getActiveThemeByName($theme_name) { $base_themes[] = $themes[$ancestor]; } + $this->prepareExtensions(); $active_theme = $this->getActiveTheme($themes[$theme_name], $base_themes); $this->state->set('theme.active_theme.' . $theme_name, $active_theme); @@ -151,47 +162,26 @@ public function getActiveTheme(Extension $theme, array $base_themes = []) { $values['name'] = $theme->getName(); // Prepare stylesheets from this theme as well as all ancestor themes. - // We work it this way so that we can have child themes override parent - // theme stylesheets easily. - // CSS file basenames to override, pointing to the final, overridden filepath. - $values['stylesheets_override'] = array(); - // CSS file basenames to remove. + // We work it this way so that we can have child themes remove CSS files + // easily from parent. $values['stylesheets_remove'] = array(); // Grab stylesheets from base theme. foreach ($base_themes as $base) { $base_theme_path = $base->getPath(); if (!empty($base->info['stylesheets-remove'])) { - foreach ($base->info['stylesheets-remove'] as $basename) { - $values['stylesheets_remove'][$basename] = $base_theme_path . '/' . $basename; - } - } - if (!empty($base->info['stylesheets-override'])) { - foreach ($base->info['stylesheets-override'] as $name) { - $basename = drupal_basename($name); - $values['stylesheets_override'][$basename] = $base_theme_path . '/' . $name; + foreach ($base->info['stylesheets-remove'] as $css_file) { + $css_file = $this->resolveStyleSheetPlaceholders($css_file); + $values['stylesheets_remove'][$css_file] = $css_file; } } } // Add stylesheets used by this theme. if (!empty($theme->info['stylesheets-remove'])) { - foreach ($theme->info['stylesheets-remove'] as $basename) { - $values['stylesheets_remove'][$basename] = $theme_path . '/' . $basename; - - if (isset($values['stylesheets_override'][$basename])) { - unset($values['stylesheets_override'][$basename]); - } - } - } - if (!empty($theme->info['stylesheets-override'])) { - foreach ($theme->info['stylesheets-override'] as $name) { - $basename = drupal_basename($name); - $values['stylesheets_override'][$basename] = $theme_path . '/' . $name; - - if (isset($values['stylesheets_remove'][$basename])) { - unset($values['stylesheets_remove'][$basename]); - } + foreach ($theme->info['stylesheets-remove'] as $css_file) { + $css_file = $this->resolveStyleSheetPlaceholders($css_file); + $values['stylesheets_remove'][$css_file] = $css_file; } } @@ -228,4 +218,36 @@ public function getActiveTheme(Extension $theme, array $base_themes = []) { return new ActiveTheme($values); } + /** + * Gets all extensions. + * + * @return array + */ + protected function prepareExtensions() { + if (!isset($this->extensions)) { + $this->extensions = array_merge($this->moduleHandler->getModuleList(), $this->themeHandler->listInfo()); + } + return $this->extensions; + } + + /** + * Resolves tokens from the stylesheets remove. + * + * @param array $list + * + * @return array + * List of stylesheets where placeholders are replaced. + */ + protected function resolveStyleSheetPlaceholders($css_file) { + $token_candidate = explode('/', $css_file)[0]; + if (!preg_match('/@[A-z0-9_-]+/', $token_candidate)) { + return $css_file; + } + + $token = substr($token_candidate, 1); + + if (isset($this->extensions[$token])) { + return str_replace($token_candidate, $this->extensions[$token]->getPath(), $css_file); + } + } } diff --git a/core/modules/system/src/Tests/Common/AttachedAssetsTest.php b/core/modules/system/src/Tests/Common/AttachedAssetsTest.php index a52db9b..d111f44 100644 --- a/core/modules/system/src/Tests/Common/AttachedAssetsTest.php +++ b/core/modules/system/src/Tests/Common/AttachedAssetsTest.php @@ -89,7 +89,7 @@ function testAddFiles() { $css = $this->assetResolver->getCssAssets($assets, FALSE); $js = $this->assetResolver->getJsAssets($assets, FALSE)[1]; - $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/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.'); $css_render_array = \Drupal::service('asset.css.collection_renderer')->render($css); @@ -470,7 +470,7 @@ function testAddJsFileWithQueryString() { $css = $this->assetResolver->getCssAssets($assets, FALSE); $js = $this->assetResolver->getJsAssets($assets, FALSE)[1]; - $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.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.'); $css_render_array = \Drupal::service('asset.css.collection_renderer')->render($css); diff --git a/core/modules/system/src/Tests/Theme/ThemeInfoTest.php b/core/modules/system/src/Tests/Theme/ThemeInfoTest.php index aeb8846..39cf160 100644 --- a/core/modules/system/src/Tests/Theme/ThemeInfoTest.php +++ b/core/modules/system/src/Tests/Theme/ThemeInfoTest.php @@ -74,18 +74,15 @@ function testStylesheets() { $this->drupalGet('theme-test/info/stylesheets'); $this->assertIdentical(1, count($this->xpath("//link[contains(@href, '$base/base-add.css')]")), "$base/base-add.css found"); - $this->assertIdentical(1, count($this->xpath("//link[contains(@href, '$base/base-override.css')]")), "$base/base-override.css found"); $this->assertIdentical(0, count($this->xpath("//link[contains(@href, 'base-remove.css')]")), "base-remove.css not found"); $this->assertIdentical(1, count($this->xpath("//link[contains(@href, '$sub/sub-add.css')]")), "$sub/sub-add.css found"); - - $this->assertIdentical(1, count($this->xpath("//link[contains(@href, '$sub/sub-override.css')]")), "$sub/sub-override.css found"); - $this->assertIdentical(1, count($this->xpath("//link[contains(@href, '$sub/base-add.sub-override.css')]")), "$sub/base-add.sub-override.css found"); - $this->assertIdentical(1, count($this->xpath("//link[contains(@href, '$sub/base-remove.sub-override.css')]")), "$sub/base-remove.sub-override.css found"); - $this->assertIdentical(0, count($this->xpath("//link[contains(@href, 'sub-remove.css')]")), "sub-remove.css not found"); $this->assertIdentical(0, count($this->xpath("//link[contains(@href, 'base-add.sub-remove.css')]")), "base-add.sub-remove.css not found"); - $this->assertIdentical(0, count($this->xpath("//link[contains(@href, 'base-override.sub-remove.css')]")), "base-override.sub-remove.css not found"); + + // Verify that CSS files with the same name are loaded from both the base theme and subtheme. + $this->assertIdentical(1, count($this->xpath("//link[contains(@href, '$base/samename.css')]")), "$base/samename.css found"); + $this->assertIdentical(1, count($this->xpath("//link[contains(@href, '$sub/samename.css')]")), "$sub/samename.css found"); } /** diff --git a/core/modules/system/tests/modules/theme_test/theme_test.libraries.yml b/core/modules/system/tests/modules/theme_test/theme_test.libraries.yml index b08521e..9ff26ee 100644 --- a/core/modules/system/tests/modules/theme_test/theme_test.libraries.yml +++ b/core/modules/system/tests/modules/theme_test/theme_test.libraries.yml @@ -2,9 +2,6 @@ theme_stylesheets_override_and_remove_test: version: VERSION css: base: - css/base-override.css: {} - css/base-override.sub-remove.css: {} css/base-remove.css: {} - css/base-remove.sub-override.css: {} css/sub-override.css: {} css/sub-remove.css: {} 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 1c07b3f..0575c7b 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 @@ -5,9 +5,5 @@ version: VERSION core: 8.x libraries: - test_basetheme/global-styling -stylesheets-override: - - base-override.css - - base-override.sub-remove.css stylesheets-remove: - - base-remove.css - - base-remove.sub-override.css + - @theme_test/css/base-remove.css 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 1c72d30..f7529ea 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 @@ -3,5 +3,5 @@ global-styling: css: base: base-add.css: {} - base-add.sub-override.css: {} base-add.sub-remove.css: {} + samename.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 b15efa9..2f96f2c 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 @@ -6,11 +6,6 @@ core: 8.x base theme: test_basetheme libraries: - test_subtheme/global-styling -stylesheets-override: - - css/sub-override.css - - css/base-add.sub-override.css - - css/base-remove.sub-override.css stylesheets-remove: - - sub-remove.css - - base-add.sub-remove.css - - base-override.sub-remove.css + - @theme_test/css/sub-remove.css + - @test_basetheme/base-add.sub-remove.css 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 efce7ae..931dffe 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 @@ -3,3 +3,4 @@ global-styling: css: base: css/sub-add.css: {} + css/samename.css: {} diff --git a/core/themes/seven/seven.info.yml b/core/themes/seven/seven.info.yml index 0f5248c..824fb85 100644 --- a/core/themes/seven/seven.info.yml +++ b/core/themes/seven/seven.info.yml @@ -9,10 +9,6 @@ version: VERSION core: 8.x libraries: - seven/global-styling -stylesheets-override: - - css/components/vertical-tabs.css - - css/components/jquery.ui/theme.css - - css/components/dialog.theme.css stylesheets-remove: - dialog.css quickedit_stylesheets: diff --git a/core/themes/seven/seven.libraries.yml b/core/themes/seven/seven.libraries.yml index f4e6d8f..dfe1f48 100644 --- a/core/themes/seven/seven.libraries.yml +++ b/core/themes/seven/seven.libraries.yml @@ -72,3 +72,21 @@ drupal.nav-tabs: - core/drupal - core/jquery.once - core/jquery.intrinsic + +vertical-tabs: + version: VERSION + css: + theme: + css/components/vertical-tabs.css: {} + +seven.jquery.ui: + version: VERSION + css: + theme: + css/components/jquery.ui/theme.css: {} + +seven.drupal.dialog: + version: VERSION + css: + theme: + css/components/dialog.theme.css: {} diff --git a/core/themes/seven/seven.theme b/core/themes/seven/seven.theme index c24035e..04a8016 100644 --- a/core/themes/seven/seven.theme +++ b/core/themes/seven/seven.theme @@ -197,3 +197,22 @@ function seven_form_node_form_alter(&$form, FormStateInterface $form_state) { $form['revision_information']['#type'] = 'container'; $form['revision_information']['#group'] = 'meta'; } + + +/** + * Implements hook_library_info_alter(). + */ +function seven_library_info_alter(&$libraries) { + if (isset($libraries['drupal.vertical-tabs'])) { + unset($libraries['drupal.vertical-tabs']['css']['component']['misc/vertical-tabs.css']); + $libraries['drupal.vertical-tabs']['dependencies'][] = 'seven/vertical-tabs'; + } + if (isset($libraries['jquery.ui'])) { + unset($libraries['jquery.ui']['css']['component']['assets/vendor/jquery.ui/themes/base/theme.css']); + $libraries['jquery.ui']['dependencies'][] = 'seven/seven.jquery.ui'; + } + if (isset($libraries['drupal.dialog'])) { + unset($libraries['drupal.dialog']['css']['component']['misc/dialog.theme.css']); + $libraries['drupal.dialog']['dependencies'][] = 'seven/seven.drupal.dialog'; + } +}