Commit 4f4b457d authored by webchick's avatar webchick

Revert "Issue #2218039 by sun, dawehner: Render the maintenance/install page...

Revert "Issue #2218039 by sun, dawehner: Render the maintenance/install page like any other HTML page."

Broke update.php.

This reverts commit 10b03890.
parent 3a27db99
......@@ -21,7 +21,6 @@
*/
use Drupal\Component\Utility\Settings;
use Drupal\Core\Page\DefaultHtmlPageRenderer;
// Change the directory to the Drupal root.
chdir('..');
......@@ -156,7 +155,13 @@ function authorize_access_allowed() {
if (!empty($output)) {
drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
print DefaultHtmlPageRenderer::renderPage($output, $page_title, 'maintenance', array(
$maintenance_page = array(
'#page' => array(
'#title' => $page_title,
),
'#theme' => 'maintenance_page',
'#content' => $output,
'#show_messages' => $show_messages,
));
);
print drupal_render($maintenance_page);
}
......@@ -16,7 +16,6 @@
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;
......@@ -122,14 +121,18 @@ function _batch_progress_page() {
// the error message.
ob_start();
$fallback = $current_set['error_message'] . '<br />' . $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 </html> anyway.
$fallback = DefaultHtmlPageRenderer::renderPage($fallback, $current_set['title'], 'maintenance', array(
'#show_messages' => FALSE,
));
$fallback = drupal_render($fallback);
list($fallback) = explode('<!--partial-->', $fallback);
print $fallback;
......
......@@ -5,7 +5,6 @@
* Functions for error handling.
*/
use Drupal\Core\Page\DefaultHtmlPageRenderer;
use Drupal\Core\Utility\Error;
use Drupal\Component\Utility\String;
use Symfony\Component\HttpFoundation\Response;
......@@ -232,7 +231,12 @@ function _drupal_log_error($error, $fatal = FALSE) {
install_display_output($output, $GLOBALS['install_state']);
}
else {
$output = DefaultHtmlPageRenderer::renderPage($message, 'Error');
$output = array(
'#theme' => 'maintenance_page',
'#title' => 'Error',
'#content' => $message,
);
$output = drupal_render($output);
}
$response = new Response($output, 500);
......
......@@ -14,7 +14,6 @@
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;
......@@ -904,7 +903,6 @@ 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.
......@@ -914,10 +912,20 @@ function install_display_output($output, $install_state) {
'#items' => install_tasks_to_display($install_state),
'#active' => $active_task,
);
$regions['sidebar_first'] = $task_list;
drupal_add_region_content('sidebar_first', drupal_render($task_list));
}
print DefaultHtmlPageRenderer::renderPage($output, $output['#title'], 'install', $regions);
$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);
exit;
}
......
......@@ -2073,26 +2073,16 @@ 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')) : '');
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'] = '';
}
$variables['tabs'] = menu_local_tabs();
// Pass the main menu and secondary menu to the template as render arrays.
if (!empty($variables['main_menu'])) {
......@@ -2133,12 +2123,10 @@ 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()
if (!defined('MAINTENANCE_MODE')) {
$variables['breadcrumb'] = array(
'#theme' => 'breadcrumb',
'#breadcrumb' => \Drupal::service('breadcrumb')->build(\Drupal::request()->attributes->all()),
);
}
$variables['breadcrumb'] = array(
'#theme' => 'breadcrumb',
'#breadcrumb' => \Drupal::service('breadcrumb')->build(\Drupal::request()->attributes->all()),
);
}
/**
......@@ -2216,6 +2204,12 @@ 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.
......@@ -2223,29 +2217,117 @@ function theme_get_suggestions($args, $base, $delimiter = '__') {
* @see system_page_build()
*/
function template_preprocess_maintenance_page(&$variables) {
// @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']) {
$classes[] = 'db-offline';
$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);
}
$attributes['class'] = $classes;
// @see system_page_build()
$attached = array(
'#attached' => array(
'library' => array(
'core/normalize',
'system/maintenance',
),
),
);
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';
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'];
}
$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'];
}
}
/**
......@@ -2253,21 +2335,20 @@ 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);
$page_object = $variables['page']['#page'];
$attributes = $page_object->getBodyAttributes();
$classes = $attributes['class'];
$classes[] = 'install-page';
$attributes['class'] = $classes;
$variables['attributes']['class'][] = 'install-page';
// 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());
......@@ -2565,11 +2646,11 @@ function drupal_common_theme() {
),
// From theme.maintenance.inc.
'maintenance_page' => array(
'render element' => 'page',
'variables' => array('content' => NULL, 'show_messages' => TRUE, 'page' => array()),
'template' => 'maintenance-page',
),
'install_page' => array(
'render element' => 'page',
'variables' => array('content' => NULL, 'show_messages' => TRUE, 'page' => array()),
'template' => 'install-page',
),
'task_list' => array(
......
......@@ -31,7 +31,6 @@ 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.
......@@ -44,6 +43,13 @@ 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 {
......
......@@ -14,7 +14,6 @@
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;
......@@ -149,13 +148,19 @@ function update_check_requirements($skip_warnings = FALSE) {
// them if the caller has indicated they should be skipped.
if ($severity == REQUIREMENT_ERROR || ($severity == REQUIREMENT_WARNING && !$skip_warnings)) {
update_task_list('requirements');
$status_report = array(
$status = array(
'#theme' => 'status_report',
'#requirements' => $requirements,
);
$status_report['#suffix'] = 'Check the messages and <a href="' . check_url(drupal_requirements_url($severity)) . '">try again</a>.';
$status_report = drupal_render($status);
$status_report .= 'Check the messages and <a href="' . check_url(drupal_requirements_url($severity)) . '">try again</a>.';
drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
print DefaultHtmlPageRenderer::renderPage($status_report, 'Requirements problem');
$maintenance_page = array(
'#theme' => 'maintenance_page',
'#title' => 'Requirements problem',
'#content' => $status_report,
);
print drupal_render($maintenance_page);
exit();
}
}
......
......@@ -7,7 +7,6 @@
namespace Drupal\Core\Controller;
use Drupal\Core\Page\DefaultHtmlPageRenderer;
use Drupal\Core\Page\HtmlPageRendererInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
......@@ -354,8 +353,15 @@ public function on500Html(FlattenException $exception, Request $request) {
drupal_set_message($message, $class, TRUE);
}
$content = t('The website has encountered an error. Please try again later.');
$output = DefaultHtmlPageRenderer::renderPage($content, t('Error'));
$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);
$response = new Response($output);
$response->setStatusCode(500, '500 Service unavailable (with message)');
......
......@@ -7,8 +7,6 @@
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;
......@@ -46,10 +44,14 @@ public function onKernelRequestMaintenance(GetResponseEvent $event) {
if ($request->attributes->get('_maintenance') != MENU_SITE_ONLINE && !($response instanceof RedirectResponse)) {
// Deliver the 503 page.
drupal_maintenance_theme();
$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'));
$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);
$response = new Response('Service unavailable', 503);
$response->setContent($content);
$event->setResponse($response);
......
......@@ -23,87 +23,4 @@ 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.
*
* This is functionally very similar to DefaultHtmlFragmentRenderer::render()
* but with the following important differences:
*
* - drupal_prepare_page() and hook_page_build() cannot be invoked on the
* maintenance and install pages, since possibly enabled page layout/block
* modules would replace the main page content with configured region
* content.
* - This function composes a complete page render array including a page
* template theme suggestion (as opposed to the main page content only).
* - The render cache and cache tags is skipped.
*
* @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. Defaults to
* 'maintenance'. The given value will be appended with '_page' to compose
* the #theme property for #type 'page' currently; e.g., 'maintenance'
* becomes 'maintenance_page'. Ultimately this parameter will be converted
* into a page template theme suggestion; i.e., 'page__$theme'.
* @param array $regions
* (optional) Additional region content to add to the page. The given array
* is added to the page render array, so this parameter may also be used to
* pass e.g. the #show_messages property for #type 'page'.
*
* @return string
* The rendered HTML page.
*
* @internal
*/
public static function renderPage($main, $title = '', $theme = 'maintenance', array $regions = array()) {
// Automatically convert the main page content into a render array.
if (!is_array($main)) {
$main = array('#markup' => $main);
}
$page = new HtmlPage('', array(), $title);
$page_array = array(
'#type' => 'page',
// @todo Change into theme suggestions "page__$theme".
'#theme' => $theme . '_page',
'#title' => $title,
'content' => array(
'system_main' => $main,
),
);
// Append region content.
$page_array += $regions;
// Add default properties.
$page_array += element_info('page');
// hook_page_build() cannot be invoked on the maintenance and install pages,
// because the application is in an unknown or special state.
// In particular on the install page, invoking hook_page_build() directly
// after e.g. Block module has been installed would *replace* the installer
// output with the configured blocks of the installer theme (loaded from
// default configuration of the installation profile).
// Allow modules and themes to alter the page render array.
// This allows e.g. themes to attach custom libraries.
\Drupal::moduleHandler()->alter('page', $page_array);
// @todo Move preparePage() before alter() above, so $page_array['#page'] is
// available in hook_page_alter(), so that HTML attributes can be altered.
$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);
}
}
......@@ -8,6 +8,10 @@
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;
/**
......@@ -40,72 +44,216 @@ protected function setUp() {
* Asserts that an array of elements is rendered properly.
*
* @param array $elements
* The render element array to test.
* @param string $expected_html
* The expected markup.
* @param string $message
* Assertion message.
* 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'.
*/
protected function assertElements(array $elements, $expected_html, $message) {
$actual_html = drupal_render($elements);
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']);
}
$out = '<table><tr>';
$out .= '<td valign="top"><pre>' . String::checkPlain($expected_html) . '</pre></td>';
$out .= '<td valign="top"><pre>' . String::checkPlain($actual_html) . '</pre></td>';
$out .= '</tr></table>';
$this->verbose($out);
// We don't care about whitespace for the sake of comparing markup.
$value = new \DOMDocument();
$value->preserveWhiteSpace = FALSE;
$value->loadXML(drupal_render($element['value']));
$this->assertIdentical($actual_html, $expected_html, String::checkPlain($message));
$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);
}
}
/**
* Tests system #type 'container'.
*/
function testContainer() {
// Basic container with no attributes.
$this->assertElements(array(
'#type' => 'container',
'#markup' => 'foo',
), "<div>foo</div>\n", "#type 'container' with no HTML attributes");
// Container with a class.
$this->assertElements(array(
'#type' => 'container',
'#markup' => 'foo',
'#attributes' => array(
'class' => 'bar',
$elements = array(
// Basic container with no attributes.
array(
'name' => "#type 'container' with no HTML attributes",
'value' => array(
'#type' => 'container',
'#markup' => 'foo',
),
'expected' => '<div>foo</div>' . "\n",
),
), '<div class="bar">foo</div>' . "\n", "#type 'container' with a class HTML attribute");
// Container with children.
$this->assertElements(array(
'#type' => 'container',
'child' => array(
'#markup' => 'foo',
// Container with a class.
array(
'name' => "#type 'container' with a class HTML attribute",
'value' => array(
'#type' => 'container',
'#markup' => 'foo',
'#attributes' => array(
'class' => 'bar',
),
),
'expected' => '<div class="bar">foo</div>' . "\n",
),
), "<div>foo</div>\n", "#type 'container' with child elements");
// Container with children.
array(
'name' => "#type 'container' with child elements",
'value' => array(
'#type' => 'container',
'child' => array(
'#markup' => 'foo',
),
),
'expected' => '<div>foo</div>' . "\n",
),
);
$this->assertElements($elements);
}
/**
* Tests system #type 'html_tag'.
*/
function testHtmlTag() {
// Test auto-closure meta tag generation.
$this->assertElements(array(
'#type' => 'html_tag',
'#tag' => 'meta',
'#attributes' => array(
'name' => 'description',
'content' => 'Drupal test',
$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' => '<meta name="description" content="Drupal test" />' . "\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>title test</title>' . "\n",
),
);
$this->assertElements($elements);
}
/**