summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorAlex Pott2013-06-22 19:36:14 (GMT)
committerAlex Pott2013-06-22 19:36:14 (GMT)
commita93de78702d6ae87d45dad8777ea7051acea2734 (patch)
tree0659a3873f31a428c03407e41e2d3453761604d2 /core
parentf36f48064966a818112964747e2d5ccd0eb16f0e (diff)
Issue #1992606 by damiankloip, pwieck: Convert system_theme_settings() to FormInterface.
Diffstat (limited to 'core')
-rw-r--r--core/includes/theme.inc2
-rw-r--r--core/lib/Drupal/Core/Controller/HtmlFormController.php6
-rw-r--r--core/modules/block/lib/Drupal/block/Tests/BlockHiddenRegionTest.php1
-rw-r--r--core/modules/color/lib/Drupal/color/Tests/ColorTest.php2
-rw-r--r--core/modules/system/lib/Drupal/system/Form/ThemeSettingsForm.php456
-rw-r--r--core/modules/system/lib/Drupal/system/Routing/RouteSubscriber.php47
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterTest.php1
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php2
-rw-r--r--core/modules/system/system.admin.inc379
-rw-r--r--core/modules/system/system.module24
-rw-r--r--core/modules/system/system.routing.yml14
-rw-r--r--core/modules/system/system.services.yml4
12 files changed, 543 insertions, 395 deletions
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 6286f65..79360fe 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1517,6 +1517,7 @@ function theme_enable($theme_list) {
$disabled_themes->save();
list_themes(TRUE);
+ Drupal::service('router.builder')->rebuild();
menu_router_rebuild();
drupal_theme_rebuild();
@@ -1552,6 +1553,7 @@ function theme_disable($theme_list) {
$disabled_themes->save();
list_themes(TRUE);
+ Drupal::service('router.builder')->rebuild();
menu_router_rebuild();
drupal_theme_rebuild();
diff --git a/core/lib/Drupal/Core/Controller/HtmlFormController.php b/core/lib/Drupal/Core/Controller/HtmlFormController.php
index 2c2fa2c..8e88b53 100644
--- a/core/lib/Drupal/Core/Controller/HtmlFormController.php
+++ b/core/lib/Drupal/Core/Controller/HtmlFormController.php
@@ -57,10 +57,12 @@ class HtmlFormController implements ContainerAwareInterface {
$request->attributes->set('form', array());
$request->attributes->set('form_state', $form_state);
$args = $this->container->get('controller_resolver')->getArguments($request, array($form_object, 'buildForm'));
- unset($args[0], $args[1]);
$request->attributes->remove('form');
$request->attributes->remove('form_state');
- $form_state['build_info']['args'] = $args;
+
+ // Remove $form and $form_state from the arguments, and re-index them.
+ unset($args[0], $args[1]);
+ $form_state['build_info']['args'] = array_values($args);
$form_id = _drupal_form_id($form_object, $form_state);
return drupal_build_form($form_id, $form_state);
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockHiddenRegionTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockHiddenRegionTest.php
index 1232420..710c53f 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockHiddenRegionTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockHiddenRegionTest.php
@@ -64,6 +64,7 @@ class BlockHiddenRegionTest extends WebTestBase {
config('system.theme')
->set('default', $theme)
->save();
+ \Drupal::service('router.builder')->rebuild();
menu_router_rebuild();
// Ensure that "block_test_theme" is set as the default theme.
diff --git a/core/modules/color/lib/Drupal/color/Tests/ColorTest.php b/core/modules/color/lib/Drupal/color/Tests/ColorTest.php
index 7dcfb1b..13627cc 100644
--- a/core/modules/color/lib/Drupal/color/Tests/ColorTest.php
+++ b/core/modules/color/lib/Drupal/color/Tests/ColorTest.php
@@ -48,6 +48,8 @@ class ColorTest extends WebTestBase {
),
);
theme_enable(array_keys($this->themes));
+ $this->container->get('router.builder')->rebuild();
+ menu_router_rebuild();
// Array filled with valid and not valid color values
$this->colorTests = array(
diff --git a/core/modules/system/lib/Drupal/system/Form/ThemeSettingsForm.php b/core/modules/system/lib/Drupal/system/Form/ThemeSettingsForm.php
new file mode 100644
index 0000000..216d0d1
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Form/ThemeSettingsForm.php
@@ -0,0 +1,456 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Form\ThemeSettingsForm.
+ */
+
+namespace Drupal\system\Form;
+
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Config\ConfigFactory;
+use Drupal\Core\Config\Context\ContextInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\system\SystemConfigFormBase;
+
+/**
+ * Displays theme configuration for entire site and individual themes.
+ */
+class ThemeSettingsForm extends SystemConfigFormBase {
+
+ /**
+ * The module handler.
+ *
+ * @var \Drupal\Core\Extension\ModuleHandlerInterface
+ */
+ protected $moduleHandler;
+
+ /**
+ * Constructs a ThemeSettingsForm object.
+ *
+ * @param \Drupal\Core\Config\ConfigFactory $config_factory
+ * The factory for configuration objects.
+ * @param \Drupal\Core\Config\Context\ContextInterface $context
+ * The configuration context to use.
+ * @param Drupal\Core\Extension\ModuleHandlerInterface
+ * The module handler instance to use.
+ */
+ public function __construct(ConfigFactory $config_factory, ContextInterface $context, ModuleHandlerInterface $module_handler) {
+ parent::__construct($config_factory, $context);
+
+ $this->moduleHandler = $module_handler;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container) {
+ return new static(
+ $container->get('config.factory'),
+ $container->get('config.context.free'),
+ $container->get('module_handler')
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFormID() {
+ return 'system_theme_settings';
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param string $theme_name
+ * The theme name.
+ */
+ public function buildForm(array $form, array &$form_state, $theme_name = '') {
+ $form = parent::buildForm($form, $form_state);
+
+ $themes = list_themes();
+
+ // Deny access if the theme is disabled or not found.
+ if (!empty($theme_name) && (empty($themes[$theme_name]) || !$themes[$theme_name]->status)) {
+ throw new NotFoundHttpException();
+ }
+
+ // Default settings are defined in theme_get_setting() in includes/theme.inc
+ if ($theme_name) {
+ $var = 'theme_' . $theme_name . '_settings';
+ $config_key = $theme_name . '.settings';
+ $themes = list_themes();
+ $features = $themes[$theme_name]->info['features'];
+ }
+ else {
+ $var = 'theme_settings';
+ $config_key = 'system.theme.global';
+ }
+
+ $form['var'] = array(
+ '#type' => 'hidden',
+ '#value' => $var
+ );
+ $form['config_key'] = array(
+ '#type' => 'hidden',
+ '#value' => $config_key
+ );
+
+ // Toggle settings
+ $toggles = array(
+ 'logo' => t('Logo'),
+ 'name' => t('Site name'),
+ 'slogan' => t('Site slogan'),
+ 'node_user_picture' => t('User pictures in posts'),
+ 'comment_user_picture' => t('User pictures in comments'),
+ 'comment_user_verification' => t('User verification status in comments'),
+ 'favicon' => t('Shortcut icon'),
+ 'main_menu' => t('Main menu'),
+ 'secondary_menu' => t('Secondary menu'),
+ );
+
+ // Some features are not always available
+ $disabled = array();
+ if (!user_picture_enabled()) {
+ $disabled['toggle_node_user_picture'] = TRUE;
+ $disabled['toggle_comment_user_picture'] = TRUE;
+ }
+ if (!$this->moduleHandler->moduleExists('comment')) {
+ $disabled['toggle_comment_user_picture'] = TRUE;
+ $disabled['toggle_comment_user_verification'] = TRUE;
+ }
+
+ $form['theme_settings'] = array(
+ '#type' => 'details',
+ '#title' => t('Toggle display'),
+ '#description' => t('Enable or disable the display of certain page elements.'),
+ );
+ foreach ($toggles as $name => $title) {
+ if ((!$theme_name) || in_array($name, $features)) {
+ $form['theme_settings']['toggle_' . $name] = array('#type' => 'checkbox', '#title' => $title, '#default_value' => theme_get_setting('features.' . $name, $theme_name));
+ // Disable checkboxes for features not supported in the current configuration.
+ if (isset($disabled['toggle_' . $name])) {
+ $form['theme_settings']['toggle_' . $name]['#disabled'] = TRUE;
+ }
+ }
+ }
+
+ if (!element_children($form['theme_settings'])) {
+ // If there is no element in the theme settings details then do not show
+ // it -- but keep it in the form if another module wants to alter.
+ $form['theme_settings']['#access'] = FALSE;
+ }
+
+ // Logo settings, only available when file.module is enabled.
+ if ((!$theme_name) || in_array('logo', $features) && $this->moduleHandler->moduleExists('file')) {
+ $form['logo'] = array(
+ '#type' => 'details',
+ '#title' => t('Logo image settings'),
+ '#attributes' => array('class' => array('theme-settings-bottom')),
+ '#states' => array(
+ // Hide the logo image settings fieldset when logo display is disabled.
+ 'invisible' => array(
+ 'input[name="toggle_logo"]' => array('checked' => FALSE),
+ ),
+ ),
+ );
+ $form['logo']['default_logo'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use the default logo supplied by the theme'),
+ '#default_value' => theme_get_setting('logo.use_default', $theme_name),
+ '#tree' => FALSE,
+ );
+ $form['logo']['settings'] = array(
+ '#type' => 'container',
+ '#states' => array(
+ // Hide the logo settings when using the default logo.
+ 'invisible' => array(
+ 'input[name="default_logo"]' => array('checked' => TRUE),
+ ),
+ ),
+ );
+ $form['logo']['settings']['logo_path'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Path to custom logo'),
+ '#default_value' => theme_get_setting('logo.path', $theme_name),
+ );
+ $form['logo']['settings']['logo_upload'] = array(
+ '#type' => 'file',
+ '#title' => t('Upload logo image'),
+ '#maxlength' => 40,
+ '#description' => t("If you don't have direct file access to the server, use this field to upload your logo.")
+ );
+ }
+
+ if ((!$theme_name) || in_array('favicon', $features) && $this->moduleHandler->moduleExists('file')) {
+ $form['favicon'] = array(
+ '#type' => 'details',
+ '#title' => t('Shortcut icon settings'),
+ '#description' => t("Your shortcut icon, or 'favicon', is displayed in the address bar and bookmarks of most browsers."),
+ '#states' => array(
+ // Hide the shortcut icon settings fieldset when shortcut icon display
+ // is disabled.
+ 'invisible' => array(
+ 'input[name="toggle_favicon"]' => array('checked' => FALSE),
+ ),
+ ),
+ );
+ $form['favicon']['default_favicon'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use the default shortcut icon supplied by the theme'),
+ '#default_value' => theme_get_setting('favicon.use_default', $theme_name),
+ );
+ $form['favicon']['settings'] = array(
+ '#type' => 'container',
+ '#states' => array(
+ // Hide the favicon settings when using the default favicon.
+ 'invisible' => array(
+ 'input[name="default_favicon"]' => array('checked' => TRUE),
+ ),
+ ),
+ );
+ $form['favicon']['settings']['favicon_path'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Path to custom icon'),
+ '#default_value' => theme_get_setting('favicon.path', $theme_name),
+ );
+ $form['favicon']['settings']['favicon_upload'] = array(
+ '#type' => 'file',
+ '#title' => t('Upload icon image'),
+ '#description' => t("If you don't have direct file access to the server, use this field to upload your shortcut icon.")
+ );
+ }
+
+ // Inject human-friendly values and form element descriptions for logo and
+ // favicon.
+ foreach (array('logo' => 'logo.png', 'favicon' => 'favicon.ico') as $type => $default) {
+ if (isset($form[$type]['settings'][$type . '_path'])) {
+ $element = &$form[$type]['settings'][$type . '_path'];
+
+ // If path is a public:// URI, display the path relative to the files
+ // directory; stream wrappers are not end-user friendly.
+ $original_path = $element['#default_value'];
+ $friendly_path = NULL;
+ if (file_uri_scheme($original_path) == 'public') {
+ $friendly_path = file_uri_target($original_path);
+ $element['#default_value'] = $friendly_path;
+ }
+
+ // Prepare local file path for description.
+ if ($original_path && isset($friendly_path)) {
+ $local_file = strtr($original_path, array('public:/' => variable_get('file_public_path', conf_path() . '/files')));
+ }
+ elseif ($theme_name) {
+ $local_file = drupal_get_path('theme', $theme_name) . '/' . $default;
+ }
+ else {
+ $local_file = path_to_theme() . '/' . $default;
+ }
+
+ $element['#description'] = t('Examples: <code>@implicit-public-file</code> (for a file in the public filesystem), <code>@explicit-file</code>, or <code>@local-file</code>.', array(
+ '@implicit-public-file' => isset($friendly_path) ? $friendly_path : $default,
+ '@explicit-file' => file_uri_scheme($original_path) !== FALSE ? $original_path : 'public://' . $default,
+ '@local-file' => $local_file,
+ ));
+ }
+ }
+
+ if ($theme_name) {
+ // Call engine-specific settings.
+ $function = $themes[$theme_name]->prefix . '_engine_settings';
+ if (function_exists($function)) {
+ $form['engine_specific'] = array(
+ '#type' => 'details',
+ '#title' => t('Theme-engine-specific settings'),
+ '#description' => t('These settings only exist for the themes based on the %engine theme engine.', array('%engine' => $themes[$theme_name]->prefix)),
+ );
+ $function($form, $form_state);
+ }
+
+ // Create a list which includes the current theme and all its base themes.
+ if (isset($themes[$theme_name]->base_themes)) {
+ $theme_keys = array_keys($themes[$theme_name]->base_themes);
+ $theme_keys[] = $theme_name;
+ }
+ else {
+ $theme_keys = array($theme_name);
+ }
+
+ // Save the name of the current theme (if any), so that we can temporarily
+ // override the current theme and allow theme_get_setting() to work
+ // without having to pass the theme name to it.
+ $default_theme = !empty($GLOBALS['theme_key']) ? $GLOBALS['theme_key'] : NULL;
+ $GLOBALS['theme_key'] = $theme_name;
+
+ // Process the theme and all its base themes.
+ foreach ($theme_keys as $theme) {
+ // Include the theme-settings.php file.
+ $filename = DRUPAL_ROOT . '/' . str_replace("/$theme.info.yml", '', $themes[$theme]->filename) . '/theme-settings.php';
+ if (file_exists($filename)) {
+ require_once $filename;
+ }
+
+ // Call theme-specific settings.
+ $function = $theme . '_form_system_theme_settings_alter';
+ if (function_exists($function)) {
+ $function($form, $form_state);
+ }
+ }
+
+ // Restore the original current theme.
+ if (isset($default_theme)) {
+ $GLOBALS['theme_key'] = $default_theme;
+ }
+ else {
+ unset($GLOBALS['theme_key']);
+ }
+ }
+
+ return $form;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function validateForm(array &$form, array &$form_state) {
+ parent::validateForm($form, $form_state);
+
+ if ($this->moduleHandler->moduleExists('file')) {
+ // Handle file uploads.
+ $validators = array('file_validate_is_image' => array());
+
+ // Check for a new uploaded logo.
+ $file = file_save_upload('logo_upload', $validators, FALSE, 0);
+ if (isset($file)) {
+ // File upload was attempted.
+ if ($file) {
+ // Put the temporary file in form_values so we can save it on submit.
+ $form_state['values']['logo_upload'] = $file;
+ }
+ else {
+ // File upload failed.
+ form_set_error('logo_upload', t('The logo could not be uploaded.'));
+ }
+ }
+
+ $validators = array('file_validate_extensions' => array('ico png gif jpg jpeg apng svg'));
+
+ // Check for a new uploaded favicon.
+ $file = file_save_upload('favicon_upload', $validators, FALSE, 0);
+ if (isset($file)) {
+ // File upload was attempted.
+ if ($file) {
+ // Put the temporary file in form_values so we can save it on submit.
+ $form_state['values']['favicon_upload'] = $file;
+ }
+ else {
+ // File upload failed.
+ form_set_error('favicon_upload', t('The favicon could not be uploaded.'));
+ }
+ }
+
+ // If the user provided a path for a logo or favicon file, make sure a file
+ // exists at that path.
+ if ($form_state['values']['logo_path']) {
+ $path = $this->validatePath($form_state['values']['logo_path']);
+ if (!$path) {
+ form_set_error('logo_path', t('The custom logo path is invalid.'));
+ }
+ }
+ if ($form_state['values']['favicon_path']) {
+ $path = $this->validatePath($form_state['values']['favicon_path']);
+ if (!$path) {
+ form_set_error('favicon_path', t('The custom favicon path is invalid.'));
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function submitForm(array &$form, array &$form_state) {
+ parent::submitForm($form, $form_state);
+
+ $config = $this->configFactory->get($form_state['values']['config_key']);
+
+ // Exclude unnecessary elements before saving.
+ form_state_values_clean($form_state);
+ unset($form_state['values']['var']);
+ unset($form_state['values']['config_key']);
+
+ $values = $form_state['values'];
+
+ // If the user uploaded a new logo or favicon, save it to a permanent location
+ // and use it in place of the default theme-provided file.
+ if ($this->moduleHandler->moduleExists('file')) {
+ if ($file = $values['logo_upload']) {
+ unset($values['logo_upload']);
+ $filename = file_unmanaged_copy($file->getFileUri());
+ $values['default_logo'] = 0;
+ $values['logo_path'] = $filename;
+ $values['toggle_logo'] = 1;
+ }
+ if ($file = $values['favicon_upload']) {
+ unset($values['favicon_upload']);
+ $filename = file_unmanaged_copy($file->getFileUri());
+ $values['default_favicon'] = 0;
+ $values['favicon_path'] = $filename;
+ $values['toggle_favicon'] = 1;
+ }
+
+ // If the user entered a path relative to the system files directory for
+ // a logo or favicon, store a public:// URI so the theme system can handle it.
+ if (!empty($values['logo_path'])) {
+ $values['logo_path'] = $this->validatePath($values['logo_path']);
+ }
+ if (!empty($values['favicon_path'])) {
+ $values['favicon_path'] = $this->validatePath($values['favicon_path']);
+ }
+
+ if (empty($values['default_favicon']) && !empty($values['favicon_path'])) {
+ $values['favicon_mimetype'] = file_get_mimetype($values['favicon_path']);
+ }
+ }
+
+ theme_settings_convert_to_config($values, $config)->save();
+
+ Cache::invalidateTags(array('content' => TRUE));
+ }
+
+ /**
+ * Helper function for the system_theme_settings form.
+ *
+ * Attempts to validate normal system paths, paths relative to the public files
+ * directory, or stream wrapper URIs. If the given path is any of the above,
+ * returns a valid path or URI that the theme system can display.
+ *
+ * @param string $path
+ * A path relative to the Drupal root or to the public files directory, or
+ * a stream wrapper URI.
+ * @return mixed
+ * A valid path that can be displayed through the theme system, or FALSE if
+ * the path could not be validated.
+ */
+ protected function validatePath($path) {
+ // Absolute local file paths are invalid.
+ if (drupal_realpath($path) == $path) {
+ return FALSE;
+ }
+ // A path relative to the Drupal root or a fully qualified URI is valid.
+ if (is_file($path)) {
+ return $path;
+ }
+ // Prepend 'public://' for relative file paths within public filesystem.
+ if (file_uri_scheme($path) === FALSE) {
+ $path = 'public://' . $path;
+ }
+ if (is_file($path)) {
+ return $path;
+ }
+ return FALSE;
+ }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/Routing/RouteSubscriber.php b/core/modules/system/lib/Drupal/system/Routing/RouteSubscriber.php
new file mode 100644
index 0000000..616955c
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Routing/RouteSubscriber.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\EventSubscriber\RouteSubscriber.
+ */
+
+namespace Drupal\system\Routing;
+
+use Drupal\Core\Routing\RouteBuildEvent;
+use Drupal\Core\Routing\RoutingEvents;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Event subscriber for routes.
+ */
+class RouteSubscriber implements EventSubscriberInterface {
+
+ /**
+ * Implements EventSubscriberInterface::getSubscribedEvents().
+ */
+ static function getSubscribedEvents() {
+ $events[RoutingEvents::DYNAMIC] = 'createSystemThemeRoutes';
+ return $events;
+ }
+
+ /**
+ * Adds dynamic system theme routes.
+ *
+ * @param \Drupal\Core\Routing\RouteBuildEvent $event
+ * The route building event.
+ */
+ public function createSystemThemeRoutes(RouteBuildEvent $event) {
+ $collection = $event->getRouteCollection();
+ foreach (list_themes() as $theme) {
+ if (!empty($theme->status)) {
+ $route = new Route('admin/appearance/settings/' . $theme->name, array(
+ '_form' => '\Drupal\system\Form\ThemeSettingsForm', 'theme_name' => $theme->name), array(
+ '_permission' => 'administer themes',
+ ));
+ $collection->add('system_theme_settings_' . $theme->name, $route);
+ }
+ }
+ }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterTest.php
index b6731ac..afb7e32 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Menu/MenuRouterTest.php
@@ -338,6 +338,7 @@ class MenuRouterTest extends WebTestBase {
// Change the menu_name parameter in menu_test.module, then force a menu
// rebuild.
menu_test_menu_name('changed');
+ \Drupal::service('router.builder')->rebuild();
menu_router_rebuild();
$menu_links = entity_load_multiple_by_properties('menu_link', array('router_path' => 'menu_name_test'));
diff --git a/core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php b/core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php
index f636849..d9e2adb 100644
--- a/core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/System/ThemeTest.php
@@ -231,6 +231,8 @@ class ThemeTest extends WebTestBase {
$this->clickLink(t('Set default'));
$this->assertEqual(config('system.theme')->get('default'), 'bartik');
+ drupal_flush_all_caches();
+
// Test the default theme on the secondary links (blocks admin page).
$this->drupalGet('admin/structure/block');
$this->assertText('Bartik(' . t('active tab') . ')', 'Default local task on blocks admin page is the default theme.');
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index c499692..957db86 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -306,385 +306,6 @@ function system_theme_default() {
}
/**
- * Form builder; display theme configuration for entire site and individual themes.
- *
- * @param $key
- * A theme name.
- * @return
- * The form structure.
- * @ingroup forms
- * @see system_theme_settings_validate()
- * @see system_theme_settings_submit()
- */
-function system_theme_settings($form, &$form_state, $key = '') {
- // Default settings are defined in theme_get_setting() in includes/theme.inc
- if ($key) {
- $var = 'theme_' . $key . '_settings';
- $config_key = $key . '.settings';
- $themes = list_themes();
- $features = $themes[$key]->info['features'];
- }
- else {
- $var = 'theme_settings';
- $config_key = 'system.theme.global';
- }
-
- $form['var'] = array('#type' => 'hidden', '#value' => $var);
- $form['config_key'] = array('#type' => 'hidden', '#value' => $config_key);
-
- // Toggle settings
- $toggles = array(
- 'logo' => t('Logo'),
- 'name' => t('Site name'),
- 'slogan' => t('Site slogan'),
- 'node_user_picture' => t('User pictures in posts'),
- 'comment_user_picture' => t('User pictures in comments'),
- 'comment_user_verification' => t('User verification status in comments'),
- 'favicon' => t('Shortcut icon'),
- 'main_menu' => t('Main menu'),
- 'secondary_menu' => t('Secondary menu'),
- );
-
- // Some features are not always available
- $disabled = array();
- if (!user_picture_enabled()) {
- $disabled['toggle_node_user_picture'] = TRUE;
- $disabled['toggle_comment_user_picture'] = TRUE;
- }
- if (!module_exists('comment')) {
- $disabled['toggle_comment_user_picture'] = TRUE;
- $disabled['toggle_comment_user_verification'] = TRUE;
- }
-
- $form['theme_settings'] = array(
- '#type' => 'details',
- '#title' => t('Toggle display'),
- '#description' => t('Enable or disable the display of certain page elements.'),
- );
- foreach ($toggles as $name => $title) {
- if ((!$key) || in_array($name, $features)) {
- $form['theme_settings']['toggle_' . $name] = array('#type' => 'checkbox', '#title' => $title, '#default_value' => theme_get_setting('features.' . $name, $key));
- // Disable checkboxes for features not supported in the current configuration.
- if (isset($disabled['toggle_' . $name])) {
- $form['theme_settings']['toggle_' . $name]['#disabled'] = TRUE;
- }
- }
- }
-
- if (!element_children($form['theme_settings'])) {
- // If there is no element in the theme settings details then do not show
- // it -- but keep it in the form if another module wants to alter.
- $form['theme_settings']['#access'] = FALSE;
- }
-
- // Logo settings, only available when file.module is enabled.
- if ((!$key) || in_array('logo', $features) && module_exists('file')) {
- $form['logo'] = array(
- '#type' => 'details',
- '#title' => t('Logo image settings'),
- '#attributes' => array('class' => array('theme-settings-bottom')),
- '#states' => array(
- // Hide the logo image settings fieldset when logo display is disabled.
- 'invisible' => array(
- 'input[name="toggle_logo"]' => array('checked' => FALSE),
- ),
- ),
- );
- $form['logo']['default_logo'] = array(
- '#type' => 'checkbox',
- '#title' => t('Use the default logo supplied by the theme'),
- '#default_value' => theme_get_setting('logo.use_default', $key),
- '#tree' => FALSE,
- );
- $form['logo']['settings'] = array(
- '#type' => 'container',
- '#states' => array(
- // Hide the logo settings when using the default logo.
- 'invisible' => array(
- 'input[name="default_logo"]' => array('checked' => TRUE),
- ),
- ),
- );
- $form['logo']['settings']['logo_path'] = array(
- '#type' => 'textfield',
- '#title' => t('Path to custom logo'),
- '#default_value' => theme_get_setting('logo.path', $key),
- );
- $form['logo']['settings']['logo_upload'] = array(
- '#type' => 'file',
- '#title' => t('Upload logo image'),
- '#maxlength' => 40,
- '#description' => t("If you don't have direct file access to the server, use this field to upload your logo.")
- );
- }
-
- if ((!$key) || in_array('favicon', $features) && module_exists('file')) {
- $form['favicon'] = array(
- '#type' => 'details',
- '#title' => t('Shortcut icon settings'),
- '#description' => t("Your shortcut icon, or 'favicon', is displayed in the address bar and bookmarks of most browsers."),
- '#states' => array(
- // Hide the shortcut icon settings fieldset when shortcut icon display
- // is disabled.
- 'invisible' => array(
- 'input[name="toggle_favicon"]' => array('checked' => FALSE),
- ),
- ),
- );
- $form['favicon']['default_favicon'] = array(
- '#type' => 'checkbox',
- '#title' => t('Use the default shortcut icon supplied by the theme'),
- '#default_value' => theme_get_setting('favicon.use_default', $key),
- );
- $form['favicon']['settings'] = array(
- '#type' => 'container',
- '#states' => array(
- // Hide the favicon settings when using the default favicon.
- 'invisible' => array(
- 'input[name="default_favicon"]' => array('checked' => TRUE),
- ),
- ),
- );
- $form['favicon']['settings']['favicon_path'] = array(
- '#type' => 'textfield',
- '#title' => t('Path to custom icon'),
- '#default_value' => theme_get_setting('favicon.path', $key),
- );
- $form['favicon']['settings']['favicon_upload'] = array(
- '#type' => 'file',
- '#title' => t('Upload icon image'),
- '#description' => t("If you don't have direct file access to the server, use this field to upload your shortcut icon.")
- );
- }
-
- // Inject human-friendly values and form element descriptions for logo and
- // favicon.
- foreach (array('logo' => 'logo.png', 'favicon' => 'favicon.ico') as $type => $default) {
- if (isset($form[$type]['settings'][$type . '_path'])) {
- $element = &$form[$type]['settings'][$type . '_path'];
-
- // If path is a public:// URI, display the path relative to the files
- // directory; stream wrappers are not end-user friendly.
- $original_path = $element['#default_value'];
- $friendly_path = NULL;
- if (file_uri_scheme($original_path) == 'public') {
- $friendly_path = file_uri_target($original_path);
- $element['#default_value'] = $friendly_path;
- }
-
- // Prepare local file path for description.
- if ($original_path && isset($friendly_path)) {
- $local_file = strtr($original_path, array('public:/' => variable_get('file_public_path', conf_path() . '/files')));
- }
- elseif ($key) {
- $local_file = drupal_get_path('theme', $key) . '/' . $default;
- }
- else {
- $local_file = path_to_theme() . '/' . $default;
- }
-
- $element['#description'] = t('Examples: <code>@implicit-public-file</code> (for a file in the public filesystem), <code>@explicit-file</code>, or <code>@local-file</code>.', array(
- '@implicit-public-file' => isset($friendly_path) ? $friendly_path : $default,
- '@explicit-file' => file_uri_scheme($original_path) !== FALSE ? $original_path : 'public://' . $default,
- '@local-file' => $local_file,
- ));
- }
- }
-
- if ($key) {
- // Call engine-specific settings.
- $function = $themes[$key]->prefix . '_engine_settings';
- if (function_exists($function)) {
- $form['engine_specific'] = array(
- '#type' => 'details',
- '#title' => t('Theme-engine-specific settings'),
- '#description' => t('These settings only exist for the themes based on the %engine theme engine.', array('%engine' => $themes[$key]->prefix)),
- );
- $function($form, $form_state);
- }
-
- // Create a list which includes the current theme and all its base themes.
- if (isset($themes[$key]->base_themes)) {
- $theme_keys = array_keys($themes[$key]->base_themes);
- $theme_keys[] = $key;
- }
- else {
- $theme_keys = array($key);
- }
-
- // Save the name of the current theme (if any), so that we can temporarily
- // override the current theme and allow theme_get_setting() to work
- // without having to pass the theme name to it.
- $default_theme = !empty($GLOBALS['theme_key']) ? $GLOBALS['theme_key'] : NULL;
- $GLOBALS['theme_key'] = $key;
-
- // Process the theme and all its base themes.
- foreach ($theme_keys as $theme) {
- // Include the theme-settings.php file.
- $filename = DRUPAL_ROOT . '/' . str_replace("/$theme.info.yml", '', $themes[$theme]->filename) . '/theme-settings.php';
- if (file_exists($filename)) {
- require_once $filename;
- }
-
- // Call theme-specific settings.
- $function = $theme . '_form_system_theme_settings_alter';
- if (function_exists($function)) {
- $function($form, $form_state);
- }
- }
-
- // Restore the original current theme.
- if (isset($default_theme)) {
- $GLOBALS['theme_key'] = $default_theme;
- }
- else {
- unset($GLOBALS['theme_key']);
- }
- }
-
- return system_config_form($form, $form_state);
-}
-
-/**
- * Validator for the system_theme_settings() form.
- */
-function system_theme_settings_validate($form, &$form_state) {
- if (module_exists('file')) {
- // Handle file uploads.
- $validators = array('file_validate_is_image' => array());
-
- // Check for a new uploaded logo.
- $file = file_save_upload('logo_upload', $validators, FALSE, 0);
- if (isset($file)) {
- // File upload was attempted.
- if ($file) {
- // Put the temporary file in form_values so we can save it on submit.
- $form_state['values']['logo_upload'] = $file;
- }
- else {
- // File upload failed.
- form_set_error('logo_upload', t('The logo could not be uploaded.'));
- }
- }
-
- $validators = array('file_validate_extensions' => array('ico png gif jpg jpeg apng svg'));
-
- // Check for a new uploaded favicon.
- $file = file_save_upload('favicon_upload', $validators, FALSE, 0);
- if (isset($file)) {
- // File upload was attempted.
- if ($file) {
- // Put the temporary file in form_values so we can save it on submit.
- $form_state['values']['favicon_upload'] = $file;
- }
- else {
- // File upload failed.
- form_set_error('favicon_upload', t('The favicon could not be uploaded.'));
- }
- }
-
- // If the user provided a path for a logo or favicon file, make sure a file
- // exists at that path.
- if ($form_state['values']['logo_path']) {
- $path = _system_theme_settings_validate_path($form_state['values']['logo_path']);
- if (!$path) {
- form_set_error('logo_path', t('The custom logo path is invalid.'));
- }
- }
- if ($form_state['values']['favicon_path']) {
- $path = _system_theme_settings_validate_path($form_state['values']['favicon_path']);
- if (!$path) {
- form_set_error('favicon_path', t('The custom favicon path is invalid.'));
- }
- }
- }
-}
-
-/**
- * Helper function for the system_theme_settings form.
- *
- * Attempts to validate normal system paths, paths relative to the public files
- * directory, or stream wrapper URIs. If the given path is any of the above,
- * returns a valid path or URI that the theme system can display.
- *
- * @param $path
- * A path relative to the Drupal root or to the public files directory, or
- * a stream wrapper URI.
- * @return mixed
- * A valid path that can be displayed through the theme system, or FALSE if
- * the path could not be validated.
- */
-function _system_theme_settings_validate_path($path) {
- // Absolute local file paths are invalid.
- if (drupal_realpath($path) == $path) {
- return FALSE;
- }
- // A path relative to the Drupal root or a fully qualified URI is valid.
- if (is_file($path)) {
- return $path;
- }
- // Prepend 'public://' for relative file paths within public filesystem.
- if (file_uri_scheme($path) === FALSE) {
- $path = 'public://' . $path;
- }
- if (is_file($path)) {
- return $path;
- }
- return FALSE;
-}
-
-/**
- * Process system_theme_settings form submissions.
- */
-function system_theme_settings_submit($form, &$form_state) {
- $config = Drupal::config($form_state['values']['config_key']);
-
- // Exclude unnecessary elements before saving.
- form_state_values_clean($form_state);
- $key = $form_state['values']['var'];
- unset($form_state['values']['var']);
- unset($form_state['values']['config_key']);
-
- $values = $form_state['values'];
-
- // If the user uploaded a new logo or favicon, save it to a permanent location
- // and use it in place of the default theme-provided file.
- if (module_exists('file')) {
- if ($file = $values['logo_upload']) {
- unset($values['logo_upload']);
- $filename = file_unmanaged_copy($file->getFileUri());
- $values['default_logo'] = 0;
- $values['logo_path'] = $filename;
- $values['toggle_logo'] = 1;
- }
- if ($file = $values['favicon_upload']) {
- unset($values['favicon_upload']);
- $filename = file_unmanaged_copy($file->getFileUri());
- $values['default_favicon'] = 0;
- $values['favicon_path'] = $filename;
- $values['toggle_favicon'] = 1;
- }
-
- // If the user entered a path relative to the system files directory for
- // a logo or favicon, store a public:// URI so the theme system can handle it.
- if (!empty($values['logo_path'])) {
- $values['logo_path'] = _system_theme_settings_validate_path($values['logo_path']);
- }
- if (!empty($values['favicon_path'])) {
- $values['favicon_path'] = _system_theme_settings_validate_path($values['favicon_path']);
- }
-
- if (empty($values['default_favicon']) && !empty($values['favicon_path'])) {
- $values['favicon_mimetype'] = file_get_mimetype($values['favicon_path']);
- }
- }
-
- theme_settings_convert_to_config($values, $config)->save();
-
- cache_invalidate_tags(array('content' => TRUE));
-}
-
-/**
* Recursively check compatibility.
*
* @param $incompatible
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 6190d04..125f807 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -710,28 +710,24 @@ function system_menu() {
$items['admin/appearance/settings'] = array(
'title' => 'Settings',
'description' => 'Configure default and theme specific settings.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('system_theme_settings'),
- 'access arguments' => array('administer themes'),
+ 'route_name' => 'system_theme_settings',
'type' => MENU_LOCAL_TASK,
- 'file' => 'system.admin.inc',
'weight' => 100,
);
- // Theme configuration subtabs.
+ // Theme configuration local tasks.
$items['admin/appearance/settings/global'] = array(
'title' => 'Global settings',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
- foreach (list_themes() as $key => $theme) {
- $items['admin/appearance/settings/' . $theme->name] = array(
- 'title' => $theme->info['name'],
- 'page arguments' => array('system_theme_settings', $theme->name),
- 'type' => MENU_LOCAL_TASK,
- 'access callback' => '_system_themes_access',
- 'access arguments' => array($key),
- 'file' => 'system.admin.inc',
- );
+ foreach (list_themes(TRUE) as $theme) {
+ if (!empty($theme->status)) {
+ $items['admin/appearance/settings/' . $theme->name] = array(
+ 'title' => $theme->info['name'],
+ 'route_name' => 'system_theme_settings_' . $theme->name,
+ 'type' => MENU_LOCAL_TASK,
+ );
+ }
}
// Modules.
diff --git a/core/modules/system/system.routing.yml b/core/modules/system/system.routing.yml
index 0ba8674..45ce1e5 100644
--- a/core/modules/system/system.routing.yml
+++ b/core/modules/system/system.routing.yml
@@ -143,3 +143,17 @@ system_admin_index:
_content: 'Drupal\system\Controller\AdminController::index'
requirements:
_permission: 'access administration pages'
+
+system_theme_settings:
+ pattern: '/admin/appearance/settings'
+ defaults:
+ _form: '\Drupal\system\Form\ThemeSettingsForm'
+ requirements:
+ _permission: 'administer themes'
+
+system_theme_settings_global:
+ pattern: '/admin/appearance/settings/global'
+ defaults:
+ _form: '\Drupal\system\Form\ThemeSettingsForm'
+ requirements:
+ _permission: 'administer themes'
diff --git a/core/modules/system/system.services.yml b/core/modules/system/system.services.yml
index 00e7821..6aefa00 100644
--- a/core/modules/system/system.services.yml
+++ b/core/modules/system/system.services.yml
@@ -13,3 +13,7 @@ services:
class: Drupal\system\LegacyBreadcrumbBuilder
tags:
- {name: breadcrumb_builder, priority: 500}
+ system.route_subscriber:
+ class: Drupal\system\Routing\RouteSubscriber
+ tags:
+ - { name: event_subscriber }