Commit e9f52b42 authored by Gábor Hojtsy's avatar Gábor Hojtsy

#141727 by merlinofchaos, dvessel, sun: restore themeability support for...

#141727 by merlinofchaos, dvessel, sun: restore themeability support for maintenance pages (regression)
parent 6d4b0a24
......@@ -369,7 +369,6 @@ function conf_init() {
*/
function drupal_get_filename($type, $name, $filename = NULL) {
static $files = array();
global $active_db;
if (!isset($files[$type])) {
$files[$type] = array();
......@@ -385,7 +384,7 @@ function drupal_get_filename($type, $name, $filename = NULL) {
// the database. This is required because this function is called both
// before we have a database connection (i.e. during installation) and
// when a database connection fails.
elseif ($active_db && (($file = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s' AND type = '%s'", $name, $type))) && file_exists($file))) {
elseif (db_is_active() && (($file = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s' AND type = '%s'", $name, $type))) && file_exists($file))) {
$files[$type][$name] = $file;
}
else {
......@@ -971,35 +970,16 @@ function _drupal_bootstrap($phase) {
}
/**
* Enables use of the theme system without requiring database access. Since
* there is not database access no theme will be enabled and the default
* themeable functions will be called. Some themeable functions can not be used
* without the full Drupal API loaded. For example, theme_page() is
* unavailable and theme_maintenance_page() must be used in its place.
* Enables use of the theme system without requiring database access.
*
* Loads and initializes the theme system for site installs, updates and when
* the site is in off-line mode. This also applies when the database fails.
*
* @see _drupal_maintenance_theme()
*/
function drupal_maintenance_theme() {
global $theme;
require_once './includes/path.inc';
require_once './includes/theme.inc';
require_once './includes/common.inc';
require_once './includes/unicode.inc';
require_once './includes/file.inc';
require_once './modules/filter/filter.module';
unicode_check();
drupal_add_css(drupal_get_path('module', 'system') .'/defaults.css', 'module');
drupal_add_css(drupal_get_path('module', 'system') .'/system.css', 'module');
drupal_add_css(drupal_get_path('module', 'system') .'/system-menus.css', 'module');
$theme = '';
// Special case registry of theme functions used by the installer
$themes = drupal_common_themes();
foreach ($themes as $hook => $info) {
if (!isset($info['file']) && !isset($info['function'])) {
$themes[$hook]['function'] = 'theme_'. $hook;
$themes[$hook]['theme path'] = 'misc';
}
}
_theme_set_registry($themes);
require_once './includes/theme.maintenance.inc';
_drupal_maintenance_theme();
}
/**
......
......@@ -2865,7 +2865,7 @@ function element_children($element) {
/**
* Provide theme registration for themes across .inc files.
*/
function drupal_common_themes() {
function drupal_common_theme() {
return array(
// theme.inc
'placeholder' => array(
......@@ -2876,6 +2876,10 @@ function drupal_common_themes() {
'template' => 'page',
),
'maintenance_page' => array(
'arguments' => array('content' => NULL, 'show_blocks' => TRUE, 'show_messages' => TRUE),
'template' => 'maintenance-page',
),
'update_page' => array(
'arguments' => array('content' => NULL, 'show_messages' => TRUE),
),
'install_page' => array(
......
......@@ -163,6 +163,14 @@ function db_set_active($name = 'default') {
return array_search($previous_db, $db_conns);
}
/**
* Returns a boolean depending on the availability of the database.
*/
function db_is_active() {
global $active_db;
return !empty($active_db);
}
/**
* Helper function for db_query().
*/
......
......@@ -615,7 +615,6 @@ function st($string, $args = array()) {
}
require_once './includes/theme.inc';
$GLOBALS['theme'] = 'theme';
// Transform arguments before inserting them
foreach ($args as $key => $value) {
switch ($key[0]) {
......
......@@ -29,7 +29,7 @@
* Initialize the theme system by loading the theme.
*/
function init_theme() {
global $theme, $user, $custom_theme, $theme_engine, $theme_key;
global $theme, $user, $custom_theme, $theme_key;
// If $theme is already set, assume the others are set, too, and do nothing
if (isset($theme)) {
......@@ -82,8 +82,10 @@ function init_theme() {
* the same information as the $theme object. It should be in
* 'oldest first' order, meaning the top level of the chain will
* be first.
* @param $registry_callback
* The callback to invoke to set the theme registry.
*/
function _init_theme($theme, $base_theme = array()) {
function _init_theme($theme, $base_theme = array(), $registry_callback = '_theme_load_registry') {
global $theme_info, $base_theme_info, $theme_engine, $theme_path;
$theme_info = $theme;
$base_theme_info = $base_theme;
......@@ -174,7 +176,8 @@ function _init_theme($theme, $base_theme = array()) {
include_once './'. $theme->owner;
}
}
_theme_load_registry($theme, $base_theme, $theme_engine);
$registry_callback($theme, $base_theme, $theme_engine);
}
/**
......@@ -394,6 +397,9 @@ function _theme_build_registry($theme, $base_theme, $theme_engine) {
/**
* Provides a list of currently available themes.
*
* If the database is active then it will be retrieved from the database.
* Otherwise it will retrieve a new list.
*
* @param $refresh
* Whether to reload the list of themes from the database.
* @return
......@@ -408,59 +414,42 @@ function list_themes($refresh = FALSE) {
if (empty($list)) {
$list = array();
$result = db_query("SELECT * FROM {system} WHERE type = '%s'", 'theme');
while ($theme = db_fetch_object($result)) {
if (file_exists($theme->filename)) {
$theme->info = unserialize($theme->info);
foreach ($theme->info['stylesheets'] as $media => $stylesheets) {
foreach ($stylesheets as $stylesheet => $path) {
if (file_exists($path)) {
$theme->stylesheets[$media][$stylesheet] = $path;
}
}
$themes = array();
// Extract from the database only when it is available.
if (db_is_active()) {
$result = db_query("SELECT * FROM {system} WHERE type = '%s'", 'theme');
while ($theme = db_fetch_object($result)) {
if (file_exists($theme->filename)) {
$theme->info = unserialize($theme->info);
$themes[] = $theme;
}
foreach ($theme->info['scripts'] as $script => $path) {
}
}
else {
// When the database is unavailable, scan the installation.
$themes = _system_theme_data();
}
foreach ($themes as $theme) {
foreach ($theme->info['stylesheets'] as $media => $stylesheets) {
foreach ($stylesheets as $stylesheet => $path) {
if (file_exists($path)) {
$theme->scripts[$script] = $path;
$theme->stylesheets[$media][$stylesheet] = $path;
}
}
if (isset($theme->info['engine'])) {
$theme->engine = $theme->info['engine'];
}
if (isset($theme->info['base theme'])) {
$theme->base_theme = $theme->info['base theme'];
}
foreach ($theme->info['scripts'] as $script => $path) {
if (file_exists($path)) {
$theme->scripts[$script] = $path;
}
$list[$theme->name] = $theme;
}
}
}
return $list;
}
/**
* Provides a list of currently available theme engines
*
* @param $refresh
* Whether to reload the list of themes from the database.
* @return
* An array of the currently available theme engines.
*/
function list_theme_engines($refresh = FALSE) {
static $list;
if ($refresh) {
unset($list);
}
if (!$list) {
$list = array();
$result = db_query("SELECT * FROM {system} WHERE type = '%s' AND status = %d ORDER BY name", 'theme_engine', '1');
while ($engine = db_fetch_object($result)) {
if (file_exists($engine->filename)) {
$engine->info = unserialize($engine->info);
$list[$engine->name] = $engine;
if (isset($theme->info['engine'])) {
$theme->engine = $theme->info['engine'];
}
if (isset($theme->info['base theme'])) {
$theme->base_theme = $theme->info['base theme'];
}
$list[$theme->name] = $theme;
}
}
......@@ -1028,117 +1017,6 @@ function theme_placeholder($text) {
return '<em>'. check_plain($text) .'</em>';
}
/**
* Generate a themed maintenance page.
*
* Note: this function is not themeable.
*
* @param $content
* The page content to show.
* @param $show_messages
* Whether to output status and error messages.
* FALSE can be useful to postpone the messages to a subsequent page.
*/
function theme_maintenance_page($content, $show_messages = TRUE) {
// Set required headers.
drupal_set_header('Content-Type: text/html; charset=utf-8');
drupal_set_html_head('<link type="text/css" rel="stylesheet" media="all" href="'. base_path() .'misc/maintenance.css" />');
drupal_set_html_head('<link type="text/css" rel="stylesheet" media="all" href="'. base_path() . drupal_get_path('module', 'system') .'/defaults.css" />');
drupal_set_html_head('<link type="text/css" rel="stylesheet" media="all" href="'. base_path() . drupal_get_path('module', 'system') .'/system.css" />');
drupal_set_html_head('<link rel="shortcut icon" href="'. base_path() .'misc/favicon.ico" type="image/x-icon" />');
// Prepare variables.
$variables = array(
'head_title' => strip_tags(drupal_get_title()),
'head' => drupal_get_html_head(),
'styles' => '',
'scripts' => drupal_get_js(),
'left' => drupal_get_content('left'),
'right' => drupal_get_content('right'),
'base_path' => base_path(),
'path_to_theme' => base_path() .'themes/garland/minnelli',
'logo' => base_path() .'themes/garland/minnelli/logo.png',
'site_title' => t('Drupal'),
'title' => drupal_get_title(),
'messages' => $show_messages ? theme('status_messages') : '',
'content' => $content,
);
$output = theme_render_template('misc/maintenance.tpl.php', $variables);
return $output;
}
/**
* Generate a themed installation page.
*
* Note: this function is not themeable.
*
* @param $content
* The page content to show.
*/
function theme_install_page($content) {
drupal_set_header('Content-Type: text/html; charset=utf-8');
drupal_add_css('misc/maintenance.css', 'module', 'all', FALSE);
drupal_set_html_head('<link rel="shortcut icon" href="'. base_path() .'misc/favicon.ico" type="image/x-icon" />');
$variables = array(
'head_title' => strip_tags(drupal_get_title()),
'head' => drupal_get_html_head(),
'styles' => drupal_get_css(),
'scripts' => drupal_get_js(),
'left' => drupal_get_content('left'),
'right' => drupal_get_content('right'),
'base_path' => base_path(),
'path_to_theme' => base_path() .'themes/garland/minnelli',
'logo' => base_path() .'themes/garland/minnelli/logo.png',
'site_title' => st('Drupal Installation'),
'title' => drupal_get_title(),
'messages' => '',
'content' => $content,
);
// Special handling of error messages
$messages = drupal_set_message();
if (isset($messages['error'])) {
$title = count($messages['error']) > 1 ? st('The following errors must be resolved before you can continue the installation process') : st('The following error must be resolved before you can continue the installation process');
$variables['messages'] .= '<h3>'. $title .':</h3>';
$variables['messages'] .= theme('status_messages', 'error');
$variables['content'] .= '<p>'. st('Please check the error messages and <a href="!url">try again</a>.', array('!url' => request_uri())) .'</p>';
}
// Special handling of status messages
if (isset($messages['status'])) {
$warnings = count($messages['status']) > 1 ? st('The following installation warnings should be carefully reviewed, but in most cases may be safely ignored') : st('The following installation warning should be carefully reviewed, but in most cases may be safely ignored');
$variables['messages'] .= '<h4>'. $title .':</h4>';
$variables['messages'] .= theme('status_messages', 'status');
}
return theme_render_template('misc/maintenance.tpl.php', $variables);
}
/**
* Return a themed list of maintenance tasks to perform.
*
* Note: this function is not themeable.
*/
function theme_task_list($items, $active = NULL) {
$done = isset($items[$active]) || $active == NULL;
$output = '<ol class="task-list">';
foreach ($items as $k => $item) {
if ($active == $k) {
$class = 'active';
$done = false;
}
else {
$class = $done ? 'done' : '';
}
$output .= '<li class="'. $class .'">'. $item .'</li>';
}
$output .= '</ol>';
return $output;
}
/**
* Return a themed set of status and/or error messages. The messages are grouped
* by type.
......@@ -1733,11 +1611,21 @@ function template_preprocess(&$variables, $hook) {
// Tell all templates where they are located.
$variables['directory'] = path_to_theme();
// Flag front page status.
$variables['is_front'] = drupal_is_front_page();
// Tell all templates by which kind of user they're viewed.
$variables['logged_in'] = ($user->uid > 0);
$variables['is_admin'] = user_access('access administration pages');
// Set default variables that depend on the database.
$variables['is_admin'] = FALSE;
$variables['is_front'] = FALSE;
$variables['logged_in'] = FALSE;
if ($variables['db_is_active'] = db_is_active()) {
// Check for administrators.
if (user_access('access administration pages')) {
$variables['is_admin'] = TRUE;
}
// Flag front page status.
$variables['is_front'] = drupal_is_front_page();
// Tell all templates by which kind of user they're viewed.
$variables['logged_in'] = ($user->uid > 0);
}
}
/**
......@@ -1750,6 +1638,9 @@ function template_preprocess(&$variables, $hook) {
* Uses the arg() function to generate a series of page template suggestions
* based on the current path.
*
* Any changes to variables in this preprocessor should also be changed inside
* template_preprocess_maintenance_page() to keep all them consistent.
*
* The $variables array contains the following arguments:
* - $content
* - $show_blocks
......@@ -1757,7 +1648,7 @@ function template_preprocess(&$variables, $hook) {
* @see page.tpl.php
*/
function template_preprocess_page(&$variables) {
/* Add favicon */
// Add favicon
if (theme_get_setting('toggle_favicon')) {
drupal_set_html_head('<link rel="shortcut icon" href="'. check_url(theme_get_setting('favicon')) .'" type="image/x-icon" />');
}
......
<?php
// $Id$
/**
* @file
* Theming for maintenance pages.
*/
/**
* Sets up the theming system for site installs, updates and when the site is
* in off-line mode. It also applies when the database is unavailable.
*
* Minnelli is always used for the initial install and update operations. In
* other cases, "settings.php" must have a "maintenance_theme" key set for the
* $conf variable in order to change the maintenance theme.
*/
function _drupal_maintenance_theme() {
global $theme, $theme_key;
// If $theme is already set, assume the others are set too, and do nothing.
if (isset($theme)) {
return;
}
require_once './includes/path.inc';
require_once './includes/theme.inc';
require_once './includes/common.inc';
require_once './includes/unicode.inc';
require_once './includes/file.inc';
require_once './includes/module.inc';
require_once './includes/database.inc';
unicode_check();
// Load module basics (needed for hook invokes).
$module_list['system']['filename'] = 'modules/system/system.module';
$module_list['filter']['filename'] = 'modules/filter/filter.module';
module_list(TRUE, FALSE, FALSE, $module_list);
drupal_load('module', 'system');
drupal_load('module', 'filter');
$themes = list_themes();
// Install and update pages are treated differently to prevent theming overrides.
if (defined('MAINTENANCE_MODE') && (MAINTENANCE_MODE == 'install' || MAINTENANCE_MODE == 'update')) {
$theme = 'minnelli';
}
else {
$theme = variable_get('maintenance_theme', 'minnelli');
}
// Store the identifier for retrieving theme settings with.
$theme_key = $theme;
// Find all our ancestor themes and put them in an array.
$base_theme = array();
$ancestor = $theme;
while ($ancestor && isset($themes[$ancestor]->base_theme)) {
$base_theme[] = $new_base_theme = $themes[$themes[$ancestor]->base_theme];
$ancestor = $themes[$ancestor]->base_theme;
}
_init_theme($themes[$theme], array_reverse($base_theme), '_theme_load_offline_registry');
// These are usually added from system_init() -except maintenance.css.
// When the database is inactive it's not called so we add it here.
drupal_add_css(drupal_get_path('module', 'system') .'/defaults.css', 'module');
drupal_add_css(drupal_get_path('module', 'system') .'/system.css', 'module');
drupal_add_css(drupal_get_path('module', 'system') .'/system-menus.css', 'module');
drupal_add_css(drupal_get_path('module', 'system') .'/maintenance.css', 'module');
}
/**
* This builds the registry when the site needs to bypass any database calls.
*/
function _theme_load_offline_registry($theme, $base_theme = NULL, $theme_engine = NULL) {
$registry = _theme_build_registry($theme, $base_theme, $theme_engine);
_theme_set_registry($registry);
}
/**
* Return a themed list of maintenance tasks to perform.
*/
function theme_task_list($items, $active = NULL) {
$done = isset($items[$active]) || $active == NULL;
$output = '<ol class="task-list">';
foreach ($items as $k => $item) {
if ($active == $k) {
$class = 'active';
$done = false;
}
else {
$class = $done ? 'done' : '';
}
$output .= '<li class="'. $class .'">'. $item .'</li>';
}
$output .= '</ol>';
return $output;
}
/**
* Generate a themed installation page.
*
* Note: this function is not themeable.
*
* @param $content
* The page content to show.
*/
function theme_install_page($content) {
drupal_set_header('Content-Type: text/html; charset=utf-8');
// Assign content.
$variables['content'] = $content;
// Delay setting the message variable so it can be processed below.
$variables['show_messages'] = FALSE;
// The maintenance preprocess function is recycled here.
template_preprocess_maintenance_page($variables);
// Special handling of error messages
$messages = drupal_set_message();
if (isset($messages['error'])) {
$title = count($messages['error']) > 1 ? st('The following errors must be resolved before you can continue the installation process') : st('The following error must be resolved before you can continue the installation process');
$variables['messages'] .= '<h3>'. $title .':</h3>';
$variables['messages'] .= theme('status_messages', 'error');
$variables['content'] .= '<p>'. st('Please check the error messages and <a href="!url">try again</a>.', array('!url' => request_uri())) .'</p>';
}
// Special handling of status messages
if (isset($messages['status'])) {
$warnings = count($messages['status']) > 1 ? st('The following installation warnings should be carefully reviewed, but in most cases may be safely ignored') : st('The following installation warning should be carefully reviewed, but in most cases may be safely ignored');
$variables['messages'] .= '<h4>'. $title .':</h4>';
$variables['messages'] .= theme('status_messages', 'status');
}
return theme_render_template('themes/garland/maintenance-page.tpl.php', $variables);
}
/**
* Generate a themed update page.
*
* Note: this function is not themeable.
*
* @param $content
* The page content to show.
* @param $show_messages
* Whether to output status and error messages.
* FALSE can be useful to postpone the messages to a subsequent page.
*/
function theme_update_page($content, $show_messages = TRUE) {
// Set required headers.
drupal_set_header('Content-Type: text/html; charset=utf-8');
// Assign content and show message flag.
$variables['content'] = $content;
$variables['show_messages'] = $show_messages;
// The maintenance preprocess function is recycled here.
template_preprocess_maintenance_page($variables);
return theme_render_template('themes/garland/maintenance-page.tpl.php', $variables);
}
/**
* The variables generated here is a mirror of template_preprocess_page().
* This preprocessor will run it's course when theme_maintenance_page() is
* invoked. It is also used in theme_install_page() and theme_update_page() to
* keep all the variables consistent.
*
* An alternate template file of "maintenance-page-offline.tpl.php" can be
* used when the database is offline to hide errors and completely replace the
* content.
*
* The $variables array contains the following arguments:
* - $content
* - $show_blocks
*
* @see maintenance-page.tpl.php
*/
function template_preprocess_maintenance_page(&$variables) {
// Add favicon
if (theme_get_setting('toggle_favicon')) {
drupal_set_html_head('<link rel="shortcut icon" href="'. check_url(theme_get_setting('favicon')) .'" type="image/x-icon" />');
}
global $theme;
// Retrieve the theme data to list all available regions.
$theme_data = _system_theme_data();
$regions = $theme_data[$theme]->info['regions'];
// Get all region content set with drupal_set_content().
foreach (array_keys($regions) as $region) {
// Assign region to a region variable.
$region_content = drupal_get_content($region);
isset($variables[$region]) ? $variables[$region] .= $region_content : $variables[$region] = $region_content;
}
// Setup layout variable.
$variables['layout'] = 'none';
if (!empty($variables['left'])) {
$variables['layout'] = 'left';
}
if (!empty($variables['right'])) {
$variables['layout'] = ($variables['layout'] == 'left') ? 'both' : 'right';
}
// Construct page title
if (drupal_get_title()) {
$head_title = array(strip_tags(drupal_get_title()), variable_get('site_name', 'Drupal'));
}
else {
$head_title = array(variable_get('site_name', 'Drupal'));
if (variable_get('site_slogan', '')) {
$head_title[] = variable_get('site_slogan', '');
}
}
$variables['head_title'] = implode(' | ', $head_title);
$variables['base_path'] = base_path();
$variables['breadcrumb'] = '';
$variables['feed_icons'] = '';
$variables['footer_message'] = filter_xss_admin(variable_get('site_footer', FALSE));
$variables['head'] = drupal_get_html_head();
$variables['help'] = '';
$variables['language'] = $GLOBALS['language'];