diff --git a/core/authorize.php b/core/authorize.php index 8715fb0..663128c 100644 --- a/core/authorize.php +++ b/core/authorize.php @@ -20,6 +20,7 @@ * @link authorize Authorized operation helper functions @endlink */ +use Drupal\Core\Page\DefaultHtmlPageRenderer; use Symfony\Component\HttpFoundation\Request; // Change the directory to the Drupal root. @@ -155,13 +156,7 @@ function authorize_access_allowed() { if (!empty($output)) { drupal_add_http_header('Content-Type', 'text/html; charset=utf-8'); - $maintenance_page = array( - '#page' => array( - '#title' => $page_title, - ), - '#theme' => 'maintenance_page', - '#content' => $output, + print DefaultHtmlPageRenderer::renderPage($output, $page_title, 'maintenance', array( '#show_messages' => $show_messages, - ); - print drupal_render($maintenance_page); + )); } diff --git a/core/includes/batch.inc b/core/includes/batch.inc index daa7b2f..153a7de 100644 --- a/core/includes/batch.inc +++ b/core/includes/batch.inc @@ -16,6 +16,7 @@ use Drupal\Component\Utility\Timer; use Drupal\Core\Batch\Percentage; +use Drupal\Core\Page\DefaultHtmlPageRenderer; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -121,18 +122,14 @@ function _batch_progress_page() { // the error message. ob_start(); $fallback = $current_set['error_message'] . '
' . $batch['error_message']; - $fallback = array( - '#theme' => 'maintenance_page', - '#title' => $current_set['title'], - '#content' => $fallback, - '#show_messages' => FALSE, - ); // We strip the end of the page using a marker in the template, so any // additional HTML output by PHP shows up inside the page rather than below // it. While this causes invalid HTML, the same would be true if we didn't, // as content is not allowed to appear after anyway. - $fallback = drupal_render($fallback); + $fallback = DefaultHtmlPageRenderer::renderPage($fallback, $current_set['title'], 'maintenance', array( + '#show_messages' => FALSE, + )); list($fallback) = explode('', $fallback); print $fallback; diff --git a/core/includes/common.inc b/core/includes/common.inc index b7dfde2..cd878c9 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -3633,11 +3633,19 @@ function drupal_prepare_page($page) { drupal_set_page_content($page); $page = element_info('page'); } + // Special front controllers (like install.php and update.php) are returning a + // proper #type 'page' render array (in order to set a custom #theme template), + // so just ensure that #type 'page' is complete. + elseif (isset($page['#type']) && $page['#type'] === 'page') { + $page += element_info('page'); + } // Modules can add elements to $page as needed in hook_page_build(). - foreach (\Drupal::moduleHandler()->getImplementations('page_build') as $module) { - $function = $module . '_page_build'; - $function($page); + if (!defined('MAINTENANCE_MODE')) { + foreach (\Drupal::moduleHandler()->getImplementations('page_build') as $module) { + $function = $module . '_page_build'; + $function($page); + } } // Modules alter the $page as needed. Blocks are populated into regions like // 'sidebar_first', 'footer', etc. @@ -3648,11 +3656,11 @@ function drupal_prepare_page($page) { // cache, even though they should be. This happens because they're rendered // directly by the theme system. // @todo Remove this once https://drupal.org/node/1869476 lands. - if (theme_get_setting('features.main_menu') && count(menu_main_menu())) { + if (!defined('MAINTENANCE_MODE') && theme_get_setting('features.main_menu') && count(menu_main_menu())) { $main_links_source = _menu_get_links_source('main_links', 'main'); $page['page_top']['#cache']['tags']['menu'][$main_links_source] = $main_links_source; } - if (theme_get_setting('features.secondary_menu') && count(menu_secondary_menu())) { + if (!defined('MAINTENANCE_MODE') && theme_get_setting('features.secondary_menu') && count(menu_secondary_menu())) { $secondary_links_source = _menu_get_links_source('secondary_links', 'account'); $page['page_top']['#cache']['tags']['menu'][$secondary_links_source] = $secondary_links_source; } @@ -3660,7 +3668,7 @@ function drupal_prepare_page($page) { // If no module has taken care of the main content, add it to the page now. // This allows the site to still be usable even if no modules that // control page regions (for example, the Block module) are enabled. - if (!$main_content_display) { + if (!$main_content_display && !isset($page['content']['system_main'])) { $page['content']['system_main'] = drupal_set_page_content(); } diff --git a/core/includes/errors.inc b/core/includes/errors.inc index 56c276f..56cf71a 100644 --- a/core/includes/errors.inc +++ b/core/includes/errors.inc @@ -5,6 +5,7 @@ * Functions for error handling. */ +use Drupal\Core\Page\DefaultHtmlPageRenderer; use Drupal\Core\Utility\Error; use Drupal\Component\Utility\String; use Symfony\Component\HttpFoundation\Response; @@ -231,12 +232,7 @@ function _drupal_log_error($error, $fatal = FALSE) { install_display_output($output, $GLOBALS['install_state']); } else { - $output = array( - '#theme' => 'maintenance_page', - '#title' => 'Error', - '#content' => $message, - ); - $output = drupal_render($output); + $output = DefaultHtmlPageRenderer::renderPage($message, 'Error'); } $response = new Response($output, 500); diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index e534003..1cb6ab5 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -14,6 +14,7 @@ use Drupal\Core\Installer\Exception\NoProfilesException; use Drupal\Core\Language\Language; use Drupal\Core\Language\LanguageManager; +use Drupal\Core\Page\DefaultHtmlPageRenderer; use Drupal\Core\StringTranslation\Translator\FileTranslation; use Drupal\Core\Extension\ExtensionDiscovery; use Drupal\Core\DependencyInjection\ContainerBuilder; @@ -899,6 +900,7 @@ function install_display_output($output, $install_state) { // Only show the task list if there is an active task; otherwise, the page // request has ended before tasks have even been started, so there is nothing // meaningful to show. + $regions = array(); if (isset($install_state['active_task'])) { // Let the theming function know when every step of the installation has // been completed. @@ -909,20 +911,10 @@ function install_display_output($output, $install_state) { '#active' => $active_task, '#variant' => 'install', ); - drupal_add_region_content('sidebar_first', drupal_render($task_list)); + $regions['sidebar_first'] = $task_list; } - $install_page = array( - '#theme' => 'install_page', - // $output has to be rendered here, because the install page template is not - // wrapped into the html template, which means that any #attached libraries - // in $output will not be loaded, because the wrapping HTML has been printed - // already. - '#content' => drupal_render($output), - ); - if (isset($output['#title'])) { - $install_page['#page']['#title'] = $output['#title']; - } - print drupal_render($install_page); + + print DefaultHtmlPageRenderer::renderPage($output, $output['#title'], 'install', $regions); exit; } diff --git a/core/includes/theme.inc b/core/includes/theme.inc index f699d4b..09488f0 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -2074,16 +2074,26 @@ function template_preprocess_page(&$variables) { $variables['base_path'] = base_path(); $variables['front_page'] = url(); - $variables['feed_icons'] = drupal_get_feeds(); $variables['language'] = $language_interface; $variables['language']->dir = $language_interface->direction ? 'rtl' : 'ltr'; $variables['logo'] = theme_get_setting('logo.url'); - $variables['main_menu'] = theme_get_setting('features.main_menu') ? menu_main_menu() : array(); - $variables['secondary_menu'] = theme_get_setting('features.secondary_menu') ? menu_secondary_menu() : array(); - $variables['action_links'] = menu_get_local_actions(); $variables['site_name'] = (theme_get_setting('features.name') ? String::checkPlain($site_config->get('name')) : ''); $variables['site_slogan'] = (theme_get_setting('features.slogan') ? filter_xss_admin($site_config->get('slogan')) : ''); - $variables['tabs'] = menu_local_tabs(); + + if (!defined('MAINTENANCE_MODE')) { + $variables['main_menu'] = theme_get_setting('features.main_menu') ? menu_main_menu() : array(); + $variables['secondary_menu'] = theme_get_setting('features.secondary_menu') ? menu_secondary_menu() : array(); + $variables['action_links'] = menu_get_local_actions(); + $variables['tabs'] = menu_local_tabs(); + $variables['feed_icons'] = drupal_get_feeds(); + } + else { + $variables['main_menu'] = array(); + $variables['secondary_menu'] = array(); + $variables['action_links'] = array(); + $variables['tabs'] = array(); + $variables['feed_icons'] = ''; + } // Pass the main menu and secondary menu to the template as render arrays. if (!empty($variables['main_menu'])) { @@ -2124,10 +2134,12 @@ function template_preprocess_page(&$variables) { // re-use the cache of an already retrieved menu containing the active link // for the current page. // @see menu_tree_page_data() - $variables['breadcrumb'] = array( - '#theme' => 'breadcrumb', - '#breadcrumb' => \Drupal::service('breadcrumb')->build(\Drupal::request()->attributes->all()), - ); + if (!defined('MAINTENANCE_MODE')) { + $variables['breadcrumb'] = array( + '#theme' => 'breadcrumb', + '#breadcrumb' => \Drupal::service('breadcrumb')->build(\Drupal::request()->attributes->all()), + ); + } } /** @@ -2205,12 +2217,6 @@ function theme_get_suggestions($args, $base, $delimiter = '__') { * * Default template: maintenance-page.html.twig. * - * The variables array generated here is a mirror of - * template_preprocess_page(). This preprocessor will run its course when - * theme_maintenance_page() is invoked. An alternate template file of - * maintenance-page--offline.html.twig can be used when the database is offline - * to hide errors and completely replace the content. - * * @param array $variables * An associative array containing: * - content - An array of page content. @@ -2218,117 +2224,29 @@ function theme_get_suggestions($args, $base, $delimiter = '__') { * @see system_page_build() */ function template_preprocess_maintenance_page(&$variables) { - $language_interface = \Drupal::languageManager()->getCurrentLanguage(); - - // Initializes attributes which are specific to the html element. - $variables['html_attributes'] = new Attribute; - - // HTML element attributes. - $variables['html_attributes']['lang'] = $language_interface->id; - $variables['html_attributes']['dir'] = $language_interface->direction ? 'rtl' : 'ltr'; - - // Add favicon - if (theme_get_setting('features.favicon')) { - $favicon = theme_get_setting('favicon.url'); - $type = theme_get_setting('favicon.mimetype'); - $build['#attached']['drupal_add_html_head_link'][][] = array( - 'rel' => 'shortcut icon', - 'href' => UrlHelper::stripDangerousProtocols($favicon), - 'type' => $type, - ); - drupal_render($build); - } - - foreach (system_region_list($GLOBALS['theme']) as $region_key => $region_name) { - if (!isset($variables[$region_key])) { - $variables[$region_key] = array(); - } - // Append region content set with drupal_add_region_content() as markup. - if ($region_content = drupal_get_region_content($region_key)) { - $variables[$region_key][]['#markup'] = $region_content; - } - } - - // Setup layout variable. - $variables['layout'] = 'none'; - if (!empty($variables['sidebar_first'])) { - $variables['layout'] = 'first'; - } - if (!empty($variables['sidebar_second'])) { - $variables['layout'] = ($variables['layout'] == 'first') ? 'both' : 'second'; - } - - $site_config = \Drupal::config('system.site'); - $site_name = $site_config->get('name'); - $site_slogan = $site_config->get('slogan'); - - // Construct the page title. - if (isset($variables['page']['#title'])) { - $head_title = array( - 'title' => strip_tags($variables['page']['#title']), - 'name' => String::checkPlain($site_config->get('name')), - ); - } - else { - $head_title = array('name' => String::checkPlain($site_name)); - if ($site_slogan) { - $head_title['slogan'] = strip_tags(filter_xss_admin($site_slogan)); - } - } - - // These are usually added from system_page_build() except maintenance.css. - // When the database is inactive it's not called so we add it here. - $default_css['library'][] = 'core/normalize'; - $default_css['library'][] = 'system/maintenance'; - $attached = array('#attached' => $default_css); - drupal_render($attached); - $variables['messages'] = array( - '#theme' => 'status_messages', - '#access' => $variables['show_messages'], - ); - - $variables['head_title_array'] = $head_title; - $variables['head_title'] = implode(' | ', $head_title); - $variables['front_page'] = url(); - $variables['help'] = ''; - $variables['language'] = $language_interface; - $variables['logo'] = theme_get_setting('logo.url'); - $variables['site_name'] = (theme_get_setting('features.name') ? String::checkPlain($site_name) : ''); - $variables['site_slogan'] = (theme_get_setting('features.slogan') ? filter_xss_admin($site_slogan) : ''); - - // Compile a list of classes that are going to be applied to the body element. - $variables['attributes']['class'][] = 'maintenance-page'; - $variables['attributes']['class'][] = 'in-maintenance'; + // @todo Rename the templates to page--maintenance + page--install. + template_preprocess_page($variables); + + $page_object = $variables['page']['#page']; + $attributes = $page_object->getBodyAttributes(); + $classes = $attributes['class']; + $classes[] = 'maintenance-page'; + $classes[] = 'in-maintenance'; if (isset($variables['db_is_active']) && !$variables['db_is_active']) { - $variables['attributes']['class'][] = 'db-offline'; - } - if ($variables['layout'] == 'both') { - $variables['attributes']['class'][] = 'two-sidebars'; - } - elseif ($variables['layout'] == 'none') { - $variables['attributes']['class'][] = 'no-sidebars'; - } - else { - $variables['attributes']['class'][] = 'one-sidebar'; - $variables['attributes']['class'][] = 'sidebar-' . $variables['layout']; + $classes[] = 'db-offline'; } + $attributes['class'] = $classes; - $variables['head'] = drupal_get_html_head(); - - // While this code is used in the installer, the language module may not be - // enabled yet (even maybe no database set up yet), but an RTL language - // selected should result in RTL stylesheets loaded properly already. - $css = _drupal_add_css(); - include_once DRUPAL_ROOT . '/core/modules/language/language.module'; - // Wrapping drupal_get_css() and drupal_get_js() in an object so they can - // be called when printed. - $variables['styles'] = new RenderWrapper('drupal_get_css', array($css)); - $variables['scripts'] = new RenderWrapper('drupal_get_js'); - - // Allow the page to define a title. - if (isset($variables['page']['#title'])) { - $variables['title'] = $variables['page']['#title']; - } + // @see system_page_build() + $attached = array( + '#attached' => array( + 'library' => array( + 'core/normalize', + 'system/maintenance', + ), + ), + ); + drupal_render($attached); } /** @@ -2336,20 +2254,21 @@ function template_preprocess_maintenance_page(&$variables) { * * Default template: install-page.html.twig. * - * The variables array generated here is a mirror of - * template_preprocess_page(). This preprocessor will run its course when - * theme_install_page() is invoked. - * * @param array $variables * An associative array containing: * - content - An array of page content. * * @see template_preprocess_maintenance_page() - * */ function template_preprocess_install_page(&$variables) { template_preprocess_maintenance_page($variables); - $variables['attributes']['class'][] = 'install-page'; + + $page_object = $variables['page']['#page']; + $attributes = $page_object->getBodyAttributes(); + $classes = $attributes['class']; + $classes[] = 'install-page'; + $attributes['class'] = $classes; + // Override the site name that is displayed on the page, since Drupal is // still in the process of being installed. $distribution_name = String::checkPlain(drupal_install_profile_distribution_name()); @@ -2464,11 +2383,11 @@ function drupal_common_theme() { ), // From theme.maintenance.inc. 'maintenance_page' => array( - 'variables' => array('content' => NULL, 'show_messages' => TRUE, 'page' => array()), + 'render element' => 'page', 'template' => 'maintenance-page', ), 'install_page' => array( - 'variables' => array('content' => NULL, 'show_messages' => TRUE, 'page' => array()), + 'render element' => 'page', 'template' => 'install-page', ), 'task_list' => array( diff --git a/core/includes/theme.maintenance.inc b/core/includes/theme.maintenance.inc index d49338d..05e911f 100644 --- a/core/includes/theme.maintenance.inc +++ b/core/includes/theme.maintenance.inc @@ -30,6 +30,7 @@ function _drupal_maintenance_theme() { require_once __DIR__ . '/unicode.inc'; require_once __DIR__ . '/file.inc'; require_once __DIR__ . '/module.inc'; + require_once __DIR__ . '/database.inc'; Unicode::check(); // Install and update pages are treated differently to prevent theming overrides. @@ -42,13 +43,6 @@ function _drupal_maintenance_theme() { } } else { - // The bootstrap was not complete. So we are operating in a crippled - // environment, we need to bootstrap just enough to allow hook invocations - // to work. See _drupal_log_error(). - if (!class_exists('Drupal\Core\Database\Database', FALSE)) { - require_once __DIR__ . '/database.inc'; - } - // Use the maintenance theme if specified, otherwise attempt to use the // default site theme. try { diff --git a/core/includes/update.inc b/core/includes/update.inc index 0bca244..58e47ba 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -14,6 +14,7 @@ use Drupal\Core\Config\FileStorage; use Drupal\Core\Config\ConfigException; use Drupal\Core\DrupalKernel; +use Drupal\Core\Page\DefaultHtmlPageRenderer; use Drupal\Core\Utility\Error; use Drupal\Component\Uuid\Uuid; use Drupal\Component\Utility\NestedArray; @@ -151,15 +152,9 @@ function update_check_requirements($skip_warnings = FALSE) { '#theme' => 'status_report', '#requirements' => $requirements, ); - $status_report = drupal_render($status); - $status_report .= 'Check the messages and try again.'; + $status_report['#suffix'] = 'Check the messages and try again.'; drupal_add_http_header('Content-Type', 'text/html; charset=utf-8'); - $maintenance_page = array( - '#theme' => 'maintenance_page', - '#title' => 'Requirements problem', - '#content' => $status_report, - ); - print drupal_render($maintenance_page); + print DefaultHtmlPageRenderer::renderPage($status_report, 'Requirements problem'); exit(); } } diff --git a/core/lib/Drupal/Core/Controller/ExceptionController.php b/core/lib/Drupal/Core/Controller/ExceptionController.php index d79567c..9302ab9 100644 --- a/core/lib/Drupal/Core/Controller/ExceptionController.php +++ b/core/lib/Drupal/Core/Controller/ExceptionController.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Controller; +use Drupal\Core\Page\DefaultHtmlPageRenderer; use Drupal\Core\Page\HtmlPageRendererInterface; use Drupal\Core\StringTranslation\TranslationInterface; use Symfony\Component\DependencyInjection\ContainerAwareInterface; @@ -353,15 +354,8 @@ public function on500Html(FlattenException $exception, Request $request) { drupal_set_message($message, $class, TRUE); } - $page_content = array( - '#theme' => 'maintenance_page', - '#content' => t('The website has encountered an error. Please try again later.'), - '#page' => array( - '#title' => t('Error'), - ), - ); - - $output = drupal_render($page_content); + $content = t('The website has encountered an error. Please try again later.'); + $output = DefaultHtmlPageRenderer::renderPage($content, t('Error')); $response = new Response($output); $response->setStatusCode(500, '500 Service unavailable (with message)'); diff --git a/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php index 93bfb42..93501d0 100644 --- a/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php @@ -7,6 +7,8 @@ namespace Drupal\Core\EventSubscriber; +use Drupal\Component\Utility\String; +use Drupal\Core\Page\DefaultHtmlPageRenderer; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\KernelEvents; @@ -44,14 +46,10 @@ public function onKernelRequestMaintenance(GetResponseEvent $event) { if ($request->attributes->get('_maintenance') != MENU_SITE_ONLINE && !($response instanceof RedirectResponse)) { // Deliver the 503 page. drupal_maintenance_theme(); - $maintenance_page = array( - '#theme' => 'maintenance_page', - '#title' => t('Site under maintenance'), - '#content' => filter_xss_admin( - t(\Drupal::config('system.maintenance')->get('message'), array('@site' => \Drupal::config('system.site')->get('name'))) - ), - ); - $content = drupal_render($maintenance_page); + $content = filter_xss_admin(String::format(\Drupal::config('system.maintenance')->get('message'), array( + '@site' => \Drupal::config('system.site')->get('name'), + ))); + $content = DefaultHtmlPageRenderer::renderPage($content, t('Site under maintenance')); $response = new Response('Service unavailable', 503); $response->setContent($content); $event->setResponse($response); diff --git a/core/lib/Drupal/Core/Page/DefaultHtmlPageRenderer.php b/core/lib/Drupal/Core/Page/DefaultHtmlPageRenderer.php index 821d42d..4ce4ab2 100644 --- a/core/lib/Drupal/Core/Page/DefaultHtmlPageRenderer.php +++ b/core/lib/Drupal/Core/Page/DefaultHtmlPageRenderer.php @@ -23,4 +23,60 @@ public function render(HtmlPage $page) { return drupal_render($render); } + /** + * Renders a page using a custom page theme hook and optional region content. + * + * Temporary shim to facilitate modernization progress for special front + * contollers (install.php, update.php, authorize.php), maintenance mode, and + * the exception handler. + * + * Do NOT use this method in your code. This method will be removed as soon + * as architecturally possible. + * + * @param array|string $main + * A render array or string containing the main page content. + * @param string $title + * (optional) The page title. + * @param string $theme + * (optional) The theme hook to use for rendering the page. The given value + * is appended with '_page' at this point, since ultimately this parameter + * will be converted into a theme template suggestion; i.e., #theme becomes + * 'page--$theme'. Defaults to 'maintenance'. + * @param array $regions + * (optional) Additional region content to add to the page. + * + * @return string + * The rendered HTML page. + * + * @internal + */ + public static function renderPage($main, $title = '', $theme = 'maintenance', array $regions = array()) { + if (!is_array($main)) { + $main = array('#markup' => $main); + } + $page = new HtmlPage('', array(), $title); + $page_array = array( + '#type' => 'page', + // @todo Change this into "page__$theme" and rename templates into + // page--maintenance and page--install. + '#theme' => $theme . '_page', + '#title' => $title, + 'content' => array( + 'system_main' => $main, + ), + ); + $page_array += $regions; + $page_array += element_info('page'); + + // Allow modules and themes to alter the page render array. + \Drupal::moduleHandler()->alter('page', $page_array); + + $page = \Drupal::service('html_fragment_renderer')->preparePage($page, $page_array); + $page->setBodyTop(drupal_render($page_array['page_top'])); + $page->setBodyBottom(drupal_render($page_array['page_bottom'])); + $page->setContent(drupal_render($page_array)); + + return \Drupal::service('html_page_renderer')->render($page); + } + } diff --git a/core/modules/system/lib/Drupal/system/Tests/Common/RenderElementTypesTest.php b/core/modules/system/lib/Drupal/system/Tests/Common/RenderElementTypesTest.php index 001b807..ef76a07 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Common/RenderElementTypesTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Common/RenderElementTypesTest.php @@ -8,10 +8,6 @@ namespace Drupal\system\Tests\Common; use Drupal\Component\Utility\String; -use Drupal\Component\Utility\UrlHelper; -use Drupal\Component\Utility\Xss; -use Drupal\Core\Language\Language; -use Drupal\Core\Template\Attribute; use Drupal\simpletest\DrupalUnitTestBase; /** @@ -44,216 +40,72 @@ protected function setUp() { * Asserts that an array of elements is rendered properly. * * @param array $elements - * An array of associative arrays describing render elements and their - * expected markup. Each item in $elements must contain the following: - * - 'name': This human readable description will be displayed on the test - * results page. - * - 'value': This is the render element to test. - * - 'expected': This is the expected markup for the element in 'value'. + * The render element array to test. + * @param string $expected_html + * The expected markup. + * @param string $message + * Assertion message. */ - function assertElements($elements) { - foreach($elements as $element) { - // More complicated "expected" strings may contain placeholders. - if (!empty($element['placeholders'])) { - $element['expected'] = String::format($element['expected'], $element['placeholders']); - } + protected function assertElements(array $elements, $expected_html, $message) { + $actual_html = drupal_render($elements); - // We don't care about whitespace for the sake of comparing markup. - $value = new \DOMDocument(); - $value->preserveWhiteSpace = FALSE; - $value->loadXML(drupal_render($element['value'])); + $out = ''; + $out .= ''; + $out .= ''; + $out .= '
' . String::checkPlain($expected_html) . '
' . String::checkPlain($actual_html) . '
'; + $this->verbose($out); - $expected = new \DOMDocument(); - $expected->preserveWhiteSpace = FALSE; - $expected->loadXML($element['expected']); - - $message = isset($element['name']) ? '"' . $element['name'] . '" input rendered correctly by drupal_render().' : NULL; - $this->assertIdentical($value->saveXML(), $expected->saveXML(), $message); - } + $this->assertIdentical($actual_html, $expected_html, String::checkPlain($message)); } /** * Tests system #type 'container'. */ function testContainer() { - $elements = array( - // Basic container with no attributes. - array( - 'name' => "#type 'container' with no HTML attributes", - 'value' => array( - '#type' => 'container', - '#markup' => 'foo', - ), - 'expected' => '
foo
' . "\n", - ), - // Container with a class. - array( - 'name' => "#type 'container' with a class HTML attribute", - 'value' => array( - '#type' => 'container', - '#markup' => 'foo', - '#attributes' => array( - 'class' => 'bar', - ), - ), - 'expected' => '
foo
' . "\n", + // Basic container with no attributes. + $this->assertElements(array( + '#type' => 'container', + '#markup' => 'foo', + ), "
foo
\n", "#type 'container' with no HTML attributes"); + + // Container with a class. + $this->assertElements(array( + '#type' => 'container', + '#markup' => 'foo', + '#attributes' => array( + 'class' => 'bar', ), - // Container with children. - array( - 'name' => "#type 'container' with child elements", - 'value' => array( - '#type' => 'container', - 'child' => array( - '#markup' => 'foo', - ), - ), - 'expected' => '
foo
' . "\n", - ), - ); + ), '
foo
' . "\n", "#type 'container' with a class HTML attribute"); - $this->assertElements($elements); + // Container with children. + $this->assertElements(array( + '#type' => 'container', + 'child' => array( + '#markup' => 'foo', + ), + ), "
foo
\n", "#type 'container' with child elements"); } /** * Tests system #type 'html_tag'. */ function testHtmlTag() { - $elements = array( - // Test auto-closure meta tag generation. - array( - 'name' => "#type 'html_tag' auto-closure meta tag generation", - 'value' => array( - '#type' => 'html_tag', - '#tag' => 'meta', - '#attributes' => array( - 'name' => 'description', - 'content' => 'Drupal test', - ), - ), - 'expected' => '' . "\n", - ), - // Test title tag generation. - array( - 'name' => "#type 'html_tag' title tag generation", - 'value' => array( - '#type' => 'html_tag', - '#tag' => 'title', - '#value' => 'title test', - ), - 'expected' => 'title test' . "\n", - ), - ); - - $this->assertElements($elements); - } - - /** - * Tests common #theme 'maintenance_page'. - */ - function testMaintenancePage() { - // We need to simulate a lot of what would happen in the preprocess, or - // there's no way to make these tests portable. - - // HTML element attributes. - $html_attributes = new Attribute; - $language_interface = \Drupal::service('language_manager')->getCurrentLanguage(); - $html_attributes['lang'] = $language_interface->id; - $html_attributes['dir'] = $language_interface->direction ? 'rtl' : 'ltr'; - - $site_config = \Drupal::config('system.site'); - - // Add favicon. - $favicon = theme_get_setting('favicon.url'); - $type = theme_get_setting('favicon.mimetype'); - drupal_add_html_head_link(array('rel' => 'shortcut icon', 'href' => UrlHelper::stripDangerousProtocols($favicon), 'type' => $type)); - - // Build CSS links. - drupal_static_reset('_drupal_add_css'); - $default_css = array( - '#attached' => array( - 'library' => array( - 'core/normalize', - 'system/maintenance', - ), + // Test auto-closure meta tag generation. + $this->assertElements(array( + '#type' => 'html_tag', + '#tag' => 'meta', + '#attributes' => array( + 'name' => 'description', + 'content' => 'Drupal test', ), - ); - drupal_render($default_css); - $css = _drupal_add_css(); - - // Simulate the expected output of a "vanilla" maintenance page. - $expected = << - - - !head - !head_title - !styles - !scripts - - -
-
- - Home - -
-

- !site_name -

-
-
-
- !title - !content -
-
- - -EOT; - - $placeholders = array( - '!html_attributes' => $html_attributes->__toString(), - '!head' => drupal_get_html_head(), - '!head_title' => $site_config->get('name'), - '!styles' => drupal_get_css($css), - '!scripts' => drupal_get_js(), - '!attributes.class' => 'maintenance-page in-maintenance no-sidebars', - '!front_page' => url(), - '!logo' => theme_get_setting('logo.url'), - '!site_name' => $site_config->get('name'), - '!title' => '', - '!content' => 'foo', - ); - - // We have to reset drupal_add_css between each test. - drupal_static_reset(); - - // Test basic string for maintenance page content. - // No page title is set, so it should default to the site name. - $elements = array( - array( - 'name' => "#theme 'maintenance_page' with content of foo", - 'value' => array( - '#theme' => 'maintenance_page', - '#content' => 'foo', - '#show_messages' => FALSE, - ), - 'expected' => $expected, - 'placeholders' => $placeholders, - ), - ); - $this->assertElements($elements); - - // Test render array for maintenance page content. - drupal_static_reset(); - $elements[0]['name'] = "#theme 'maintenance_page' with content as a render array"; - $elements[0]['value']['#content'] = array('#markup' => 'foo'); - // Testing with a page title, which should be combined with the site name. - $title = t('A non-empty title'); - $elements[0]['value']['#page']['#title'] = $title; - $elements[0]['placeholders']['!title'] = '

' . $title . '

'; - $elements[0]['placeholders']['!head_title'] = strip_tags($title) . ' | ' . String::checkPlain($site_config->get('name')); - $this->assertElements($elements); + ), '' . "\n", "#type 'html_tag' auto-closure meta tag generation"); + + // Test title tag generation. + $this->assertElements(array( + '#type' => 'html_tag', + '#tag' => 'title', + '#value' => 'title test', + ), "title test\n", "#type 'html_tag' title tag generation"); } } diff --git a/core/modules/system/templates/install-page.html.twig b/core/modules/system/templates/install-page.html.twig index 031013e..ad1c04c 100644 --- a/core/modules/system/templates/install-page.html.twig +++ b/core/modules/system/templates/install-page.html.twig @@ -3,24 +3,14 @@ * @file * Default theme implementation to display a Drupal installation page. * - * All the available variables are mirrored in html.html.twig and - * page.html.twig. Some may be blank but they are provided for consistency. + * All available variables are mirrored in page.html.twig. + * Some may be blank but they are provided for consistency. * * @see template_preprocess_install_page() * * @ingroup themeable */ #} - - - - {{ head }} - {{ head_title }} - {{ styles }} - {{ scripts }} - - -
@@ -41,26 +31,25 @@

{{ title }}

{% endif %} {{ messages }} - {{ content }} + {{ page.content }} - {% if sidebar_first %} + {% if page.sidebar_first %} {# /.l-sidebar-first #} {% endif %} - {% if sidebar_second %} + {% if page.sidebar_second %} {# /.l-sidebar-second #} {% endif %} - {% if footer %} + {% if page.footer %}
- {{ footer }} + {{ page.footer }}
{% endif %} - - +
{# /.l-container #} diff --git a/core/modules/system/templates/maintenance-page.html.twig b/core/modules/system/templates/maintenance-page.html.twig index b5275c7..3b5a59e 100644 --- a/core/modules/system/templates/maintenance-page.html.twig +++ b/core/modules/system/templates/maintenance-page.html.twig @@ -3,7 +3,7 @@ * @file * Default theme implementation to display a single Drupal page while offline. * - * All of the available variables are mirrored in html.html.twig. + * All available variables are mirrored in page.html.twig. * Some may be blank but they are provided for consistency. * * @see template_preprocess_maintenance_page() @@ -11,16 +11,6 @@ * @ingroup themeable */ #} - - - - {{ head }} - {{ head_title }} - {{ styles }} - {{ scripts }} - - -
@@ -53,7 +43,7 @@ {{ messages }} - {{ content }} + {{ page.content }} {% if page.sidebar_first %} @@ -75,6 +65,3 @@ {% endif %}
{# /.l-container #} - - - diff --git a/core/themes/bartik/bartik.theme b/core/themes/bartik/bartik.theme index 642674c..176b798 100644 --- a/core/themes/bartik/bartik.theme +++ b/core/themes/bartik/bartik.theme @@ -94,7 +94,6 @@ function bartik_preprocess_maintenance_page(&$variables) { if (!$variables['db_is_active']) { $variables['site_name'] = ''; } - $variables['styles'] = new RenderWrapper('drupal_get_css'); // Normally we could attach libraries via hook_page_alter(), but when the // database is inactive it's not called so we add them here. $libraries = array( @@ -104,6 +103,7 @@ function bartik_preprocess_maintenance_page(&$variables) { ), ), ); + drupal_render($libraries); // Set the options that apply to both page and maintenance page. _bartik_process_page($variables); diff --git a/core/themes/bartik/templates/maintenance-page.html.twig b/core/themes/bartik/templates/maintenance-page.html.twig index b29cafa..604e176 100644 --- a/core/themes/bartik/templates/maintenance-page.html.twig +++ b/core/themes/bartik/templates/maintenance-page.html.twig @@ -3,27 +3,13 @@ * @file * Bartik's theme implementation to display a single Drupal page while offline. * - * All of the available variables are mirrored in html.html.twig. + * All available variables are mirrored in page.html.twig. * * @see template_preprocess_maintenance_page() * * @ingroup themeable */ #} - - - - {{ head }} - {{ head_title }} - {{ styles }} - {{ scripts }} - - - - -
- - - diff --git a/core/themes/seven/seven.theme b/core/themes/seven/seven.theme index 6f5ce6b..9c47478 100644 --- a/core/themes/seven/seven.theme +++ b/core/themes/seven/seven.theme @@ -269,8 +269,11 @@ function seven_element_info_alter(&$type) { * Implements hook_preprocess_install_page(). */ function seven_preprocess_install_page(&$variables) { - $variables['styles'] = new RenderWrapper('drupal_get_css'); - $variables['scripts'] = new RenderWrapper('drupal_get_js'); + $page_object = $variables['page']['#page']; + $attributes = $page_object->getHtmlAttributes(); + $classes = $attributes['class']; + $classes[] = 'install-background'; + $attributes['class'] = $classes; // Normally we could attach libraries via hook_page_alter(), but when the // database is inactive it's not called so we add them here. diff --git a/core/themes/seven/templates/install-page.html.twig b/core/themes/seven/templates/install-page.html.twig index 81ddece..e7903e6 100644 --- a/core/themes/seven/templates/install-page.html.twig +++ b/core/themes/seven/templates/install-page.html.twig @@ -3,8 +3,7 @@ * @file * Seven theme implementation to display a Drupal installation page. * - * All the available variables are mirrored in html.html.twig and - * page.html.twig. + * All available variables are mirrored in page.html.twig. * Some may be blank but they are provided for consistency. * * @see template_preprocess_install_page() @@ -12,16 +11,6 @@ * @ingroup themeable */ #} - - - - {{ head }} - {{ head_title }} - {{ styles }} - {{ scripts }} - - -
@@ -37,9 +26,9 @@ {% endif %}
- {% if sidebar_first %} + {% if page.sidebar_first %} {# /.l-sidebar-first #} {% endif %} @@ -48,22 +37,19 @@

{{ title }}

{% endif %} {{ messages }} - {{ content }} + {{ page.content }} - {% if sidebar_second %} + {% if page.sidebar_second %} {# /.l-sidebar-second #} {% endif %} - {% if footer %} + {% if page.page_bottom %}
- {{ footer }} + {{ page.page_bottom }}
{% endif %}
{# /.l-container #} - - - diff --git a/core/themes/seven/templates/maintenance-page.html.twig b/core/themes/seven/templates/maintenance-page.html.twig index dc691c1..2170d36 100644 --- a/core/themes/seven/templates/maintenance-page.html.twig +++ b/core/themes/seven/templates/maintenance-page.html.twig @@ -3,26 +3,14 @@ * @file * Seven's theme implementation to display a single Drupal page while offline. * - * All of the available variables are mirrored in html.html.twig. + * All available variables are mirrored in page.html.twig. + * Some may be blank but they are provided for consistency. * * @see template_preprocess_maintenance_page() - * @see seven_preprocess_maintenance_page() * * @ingroup themeable */ #} - - - - {{ head_title }} - {{ head }} - {{ styles }} - {{ scripts }} - - - - {{ page_top }} -
{% if title %}

{{ title }}

{% endif %} @@ -34,25 +22,22 @@ {% if logo %} {% endif %} - {{ sidebar_first }} + {{ page.sidebar_first }}
{% if messages %}
{{ messages }}
{% endif %} - {% if help %} + {% if page.help %}
- {{ help }} + {{ page.help }}
{% endif %} - {{ content }} + {{ page.content }}
- - - diff --git a/core/themes/seven/templates/page.html.twig b/core/themes/seven/templates/page.html.twig index 77dde87..2caeec2 100644 --- a/core/themes/seven/templates/page.html.twig +++ b/core/themes/seven/templates/page.html.twig @@ -50,13 +50,13 @@ * comment/reply/12345). * * Regions: - * - page.header: Items for the header region. + * - page.page_top: Items for the header region. * - page.highlighted: Items for the highlighted content region. * - page.help: Dynamic help text, mostly for admin pages. * - page.content: The main content of the current page. * - page.sidebar_first: Items for the first sidebar. * - page.sidebar_second: Items for the second sidebar. - * - page.footer: Items for the footer region. + * - page.page_bottom: Items for the footer region. * * @see template_preprocess_page() * @see seven_preprocess_page() diff --git a/core/update.php b/core/update.php index a2de6fc..61bba33 100644 --- a/core/update.php +++ b/core/update.php @@ -16,6 +16,7 @@ use Drupal\Component\Utility\Settings; use Drupal\Core\DrupalKernel; +use Drupal\Core\Page\DefaultHtmlPageRenderer; use Drupal\Core\Update\Form\UpdateScriptSelectionForm; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -457,18 +458,8 @@ function update_task_list($active = NULL) { } else { drupal_add_http_header('Content-Type', 'text/html; charset=utf-8'); - $maintenance_page = array( - '#theme' => 'maintenance_page', - // $output has to be rendered here, because the maintenance page template - // is not wrapped into the html template, which means that any #attached - // libraries in $output will not be loaded, because the wrapping HTML has - // been printed already. - '#content' => drupal_render($output), + print DefaultHtmlPageRenderer::renderPage($output, $output['#title'], 'maintenance', array( '#show_messages' => !$progress_page, - ); - if (isset($output['#title'])) { - $maintenance_page['#page']['#title'] = $output['#title']; - } - print drupal_render($maintenance_page); + )); } }