diff --git a/core/includes/menu.inc b/core/includes/menu.inc index 2fd7b52..3f1ec20 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -1617,6 +1617,9 @@ function theme_menu_link(array $variables) { */ function theme_menu_local_task($variables) { $link = $variables['element']['#link']; + $link += array( + 'localized_options' => array(), + ); $link_text = $link['title']; if (!empty($variables['element']['#active'])) { @@ -1863,8 +1866,8 @@ function menu_local_tasks($level = 0) { $data = &drupal_static(__FUNCTION__); $root_path = &drupal_static(__FUNCTION__ . ':root_path', ''); $empty = array( - 'tabs' => array('count' => 0, 'output' => array()), - 'actions' => array('count' => 0, 'output' => array()), + 'tabs' => array('output' => array()), + 'actions' => array('output' => array()), 'root_path' => &$root_path, ); @@ -1916,7 +1919,6 @@ function menu_local_tasks($level = 0) { // Tab parenting may skip levels, so the number of parts in the path may not // equal the depth. Thus we use the $depth counter (offset by 1000 for ksort). $depth = 1001; - $actions['count'] = 0; $actions['output'] = array(); while (isset($children[$path])) { $tabs_current = array(); @@ -1981,9 +1983,7 @@ function menu_local_tasks($level = 0) { } } $path = $next_path; - $tabs[$depth]['count'] = $tab_count; $tabs[$depth]['output'] = $tabs_current; - $actions['count'] += $action_count; $actions['output'] = array_merge($actions['output'], $actions_current); $depth++; } @@ -2046,7 +2046,6 @@ function menu_local_tasks($level = 0) { } $path = $next_path; $parent = $next_parent; - $tabs[$depth]['count'] = $count; $tabs[$depth]['output'] = $tabs_current; $depth--; } @@ -2183,7 +2182,7 @@ function menu_contextual_links($module, $parent_path, $args) { function menu_primary_local_tasks() { $links = menu_local_tasks(0); // Do not display single tabs. - return ($links['tabs']['count'] > 1 ? $links['tabs']['output'] : ''); + return count($links['tabs']['output']) > 1 ? $links['tabs']['output'] : ''; } /** @@ -2192,7 +2191,7 @@ function menu_primary_local_tasks() { function menu_secondary_local_tasks() { $links = menu_local_tasks(1); // Do not display single tabs. - return ($links['tabs']['count'] > 1 ? $links['tabs']['output'] : ''); + return count($links['tabs']['output']) > 1 ? $links['tabs']['output'] : ''; } /** diff --git a/core/includes/module.inc b/core/includes/module.inc index ab45576..fc66bb8 100644 --- a/core/includes/module.inc +++ b/core/includes/module.inc @@ -31,7 +31,7 @@ function module_load_all($bootstrap = FALSE) { $has_run = &$drupal_static_fast['has_run']; if (isset($bootstrap)) { - $type = $bootstrap ? 'bootstrap' : 'module_enabled'; + $type = $bootstrap ? 'bootstrap' : 'module'; foreach (module_list($type) as $module) { drupal_load('module', $module); } @@ -54,7 +54,7 @@ function module_load_all($bootstrap = FALSE) { * * @param string $type * The type of list to return: - * - module_enabled: All enabled modules. + * - module: All enabled modules. * - bootstrap: All enabled modules required for bootstrap. * @param array $fixed_list * (optional) An array of module names to override the list of modules. This @@ -66,7 +66,7 @@ function module_load_all($bootstrap = FALSE) { * An associative array whose keys and values are the names of the modules in * the list. */ -function module_list($type = 'module_enabled', array $fixed_list = NULL) { +function module_list($type = 'module', array $fixed_list = NULL) { // This static is only used for $fixed_list. $module_list = &drupal_static(__FUNCTION__); @@ -102,13 +102,13 @@ function module_list_reset() { * * @param $type * The type of list to return: - * - module_enabled: All enabled modules. + * - module: All enabled modules. * - bootstrap: All enabled modules required for bootstrap. - * - theme: All themes. + * - theme: All enabled themes. * * @return * An associative array of modules or themes, keyed by name. For $type - * 'bootstrap' and 'module_enabled', the array values equal the keys. + * 'bootstrap' and 'module', the array values equal the keys. * For $type 'theme', the array values are objects representing the * respective database row, with the 'info' property already unserialized. * @@ -144,13 +144,13 @@ function system_list($type) { $lists['bootstrap'] = array_keys($bootstrap_list); } // Otherwise build the list for enabled modules and themes. - elseif (!isset($lists['module_enabled'])) { + elseif (!isset($lists['module'])) { if ($cached = cache('bootstrap')->get('system_list')) { $lists = $cached->data; } - else { + if (!isset($lists[$type])) { $lists = array( - 'module_enabled' => array(), + 'module' => array(), 'theme' => array(), 'filepaths' => array(), ); @@ -159,11 +159,11 @@ function system_list($type) { // Drupal installations, which might have modules installed in different // locations in the file system. The ordering here must also be // consistent with the one used in module_implements(). - $result = db_query("SELECT * FROM {system} WHERE type = 'theme' OR (type = 'module' AND status = 1) ORDER BY weight ASC, name ASC"); + $result = db_query("SELECT * FROM {system} WHERE (type = 'theme' OR type = 'module') AND status = 1 ORDER BY weight ASC, name ASC"); foreach ($result as $record) { // Build a list of all enabled modules. if ($record->type == 'module') { - $lists['module_enabled'][$record->name] = $record->name; + $lists['module'][$record->name] = $record->name; } // Build a list of themes. if ($record->type == 'theme') { @@ -171,9 +171,7 @@ function system_list($type) { $lists['theme'][$record->name] = $record; } // Build a list of filenames so drupal_get_filename can use it. - if ($record->status) { - $lists['filepaths'][] = array('type' => $record->type, 'name' => $record->name, 'filepath' => $record->filename); - } + $lists['filepaths'][] = array('type' => $record->type, 'name' => $record->name, 'filepath' => $record->filename); } foreach ($lists['theme'] as $key => $theme) { if (!empty($theme->info['base theme'])) { diff --git a/core/includes/theme.inc b/core/includes/theme.inc index f807979..7e875bf 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -37,6 +37,34 @@ */ /** + * Loads a theme. + * + * @param string $name + * The name of a theme to load. + * + * @return + * The loaded theme object for $name, or FALSE if the passed $name does not + * exist or is not enabled. + */ +function theme_load($name) { + $themes = list_themes(); + if (isset($themes[$name]) && drupal_theme_access($themes[$name])) { + return $themes[$name]; + } + return FALSE; +} + +/** + * Menu title callback; Returns the sanitized human-readable name of a theme. + * + * @param $theme + * The theme object to return the title for. + */ +function _theme_menu_title($theme) { + return check_plain($theme->info['name']); +} + +/** * Determines if a theme is available to use. * * @param $theme @@ -47,11 +75,18 @@ * FALSE otherwise. */ function drupal_theme_access($theme) { + // Early-return for potentially bogus '0', FALSE, or NULL values. + if (empty($theme)) { + return FALSE; + } if (is_object($theme)) { return !empty($theme->status); } else { $themes = list_themes(); + if (!isset($themes[$theme])) { + return FALSE; + } return !empty($themes[$theme]->status); } } @@ -652,14 +687,14 @@ function _theme_build_registry($theme, $base_theme, $theme_engine) { * declare this theme as their base theme. */ function list_themes($refresh = FALSE) { - $list = &drupal_static(__FUNCTION__, array()); + $list = &drupal_static(__FUNCTION__); if ($refresh) { - $list = array(); + $list = NULL; system_list_reset(); } - if (empty($list)) { + if (!isset($list)) { $list = array(); $themes = array(); // Extract from the database only when it is available. diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index 869d4ee..b0a7947 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -45,7 +45,7 @@ public function registerBundles() { // @todo Remove the necessity of calling system_list() to find out which // bundles exist. See http://drupal.org/node/1331486 - $modules = array_keys(system_list('module_enabled')); + $modules = array_keys(system_list('module')); foreach ($modules as $module) { $camelized = ContainerBuilder::camelize($module); $class = "Drupal\\{$module}\\{$camelized}Bundle"; diff --git a/core/modules/block/block.admin.inc b/core/modules/block/block.admin.inc index aa018da..bbbffbc 100644 --- a/core/modules/block/block.admin.inc +++ b/core/modules/block/block.admin.inc @@ -33,6 +33,9 @@ function block_admin_display($theme = NULL) { // If theme is not specifically set, rehash for the current theme. $theme = $theme_key; } + elseif (is_object($theme)) { + $theme = $theme->name; + } // Fetch and sort blocks. $blocks = block_admin_display_prepare_blocks($theme); diff --git a/core/modules/block/block.module b/core/modules/block/block.module index 4a3d6b9..a563ca6 100644 --- a/core/modules/block/block.module +++ b/core/modules/block/block.module @@ -62,11 +62,21 @@ function block_help($path, $arg) { case 'admin/structure/block/add': return '

' . t('Use this page to create a new custom block.') . '

'; } - if ($arg[0] == 'admin' && $arg[1] == 'structure' && $arg['2'] == 'block' && (empty($arg[3]) || $arg[3] == 'list')) { - $demo_theme = !empty($arg[4]) ? $arg[4] : variable_get('theme_default', 'stark'); - $themes = list_themes(); + + if ($arg[0] === 'admin' && $arg[1] === 'structure' && $arg['2'] === 'block' && (empty($arg[3]) || $arg[3] === 'list')) { $output = '

' . t('This page provides a drag-and-drop interface for assigning a block to a region, and for controlling the order of blocks within regions. Since not all themes implement the same regions, or display regions in the same way, blocks are positioned on a per-theme basis. Remember that your changes will not be saved until you click the Save blocks button at the bottom of the page. Click the configure link next to each block to configure its specific title and visibility settings.') . '

'; - $output .= '

' . l(t('Demonstrate block regions (@theme)', array('@theme' => $themes[$demo_theme]->info['name'])), 'admin/structure/block/demo/' . $demo_theme) . '

'; + if (!empty($arg[4])) { + if (drupal_theme_access($arg[4])) { + $demo_theme = $arg[4]; + } + } + else { + $demo_theme = variable_get('theme_default', 'stark'); + } + if (isset($demo_theme)) { + $themes = list_themes(); + $output .= '

' . l(t('Demonstrate block regions (@theme)', array('@theme' => $themes[$demo_theme]->info['name'])), 'admin/structure/block/demo/' . $demo_theme) . '

'; + } return $output; } } @@ -141,39 +151,66 @@ function block_menu() { 'type' => MENU_LOCAL_ACTION, 'file' => 'block.admin.inc', ); - foreach (list_themes() as $key => $theme) { - $items['admin/structure/block/list/' . $key] = array( - 'title' => check_plain($theme->info['name']), - 'page arguments' => array($key), - 'type' => $key == $default_theme ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, - 'weight' => $key == $default_theme ? -10 : 0, - 'access callback' => '_block_themes_access', - 'access arguments' => array($key), - 'file' => 'block.admin.inc', - ); - if ($key != $default_theme) { - $items['admin/structure/block/list/' . $key . '/add'] = array( - 'title' => 'Add block', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('block_add_block_form'), - 'access arguments' => array('administer blocks'), - 'type' => MENU_LOCAL_ACTION, - 'file' => 'block.admin.inc', + + $items['admin/structure/block/list/%theme'] = array( + 'title' => 'Theme blocks', + 'title callback' => '_theme_menu_title', + 'title arguments' => array(4), + 'page callback' => 'block_admin_display', + 'page arguments' => array(4), + 'type' => MENU_LOCAL_TASK, + 'access callback' => '_block_themes_access', + 'access arguments' => array(4), + 'file' => 'block.admin.inc', + ); + $items['admin/structure/block/list/%theme/add'] = array( + 'title' => 'Add block', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('block_add_block_form'), + 'access arguments' => array('administer blocks'), + 'type' => MENU_LOCAL_ACTION, + 'file' => 'block.admin.inc', + ); + $items['admin/structure/block/demo/%theme'] = array( + 'title' => 'Theme block region demo', + 'title callback' => '_theme_menu_title', + 'title arguments' => array(4), + 'page callback' => 'block_admin_demo', + 'page arguments' => array(4), + 'type' => MENU_CALLBACK, + 'access callback' => '_block_themes_access', + 'access arguments' => array(4), + 'theme callback' => '_block_custom_theme', + 'theme arguments' => array(4), + 'file' => 'block.admin.inc', + ); + return $items; +} + +/** + * Implements hook_menu_local_tasks_alter(). + */ +function block_menu_local_tasks_alter(&$data, $router_item, $root_path) { + if ($root_path == 'admin/structure/block' || strpos($root_path, 'admin/structure/block/list') === 0) { + foreach ($data['tabs'][0]['output'] as &$task) { + $task['#active'] = FALSE; + } + $data['tabs'][0]['output'] = array(); + $default_theme = variable_get('default_theme', 'stark'); + $current_theme = isset($router_item['original_map'][4]) ? $router_item['original_map'][4] : $default_theme; + $themes = list_themes(); + foreach ($themes as $theme) { + $data['tabs'][0]['output'][] = array( + '#theme' => 'menu_local_task', + '#link' => array( + 'title' => $theme->info['name'], + 'href' => 'admin/structure/block/list/' . $theme->name, + ), + '#active' => $theme->name === $current_theme, + '#weight' => $theme->name === $default_theme ? -10 : 0, ); } - $items['admin/structure/block/demo/' . $key] = array( - 'title' => check_plain($theme->info['name']), - 'page callback' => 'block_admin_demo', - 'page arguments' => array($key), - 'type' => MENU_CALLBACK, - 'access callback' => '_block_themes_access', - 'access arguments' => array($key), - 'theme callback' => '_block_custom_theme', - 'theme arguments' => array($key), - 'file' => 'block.admin.inc', - ); } - return $items; } /** @@ -208,7 +245,9 @@ function _block_themes_access($theme) { function _block_custom_theme($theme = NULL) { // We return exactly what was passed in, to guarantee that the page will // always be displayed using the theme whose blocks are being configured. - return $theme; + if (isset($theme->name)) { + return $theme->name; + } } /** @@ -412,6 +451,10 @@ function _block_rehash($theme = NULL) { } $regions = system_region_list($theme); + if (is_object($theme)) { + $theme = $theme->name; + } + // These are the blocks the function will return. $blocks = array(); // These are the blocks defined by code and modified by the database. diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockAdminThemeTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockAdminThemeTest.php index c3a220f..e80a053 100644 --- a/core/modules/block/lib/Drupal/block/Tests/BlockAdminThemeTest.php +++ b/core/modules/block/lib/Drupal/block/Tests/BlockAdminThemeTest.php @@ -39,7 +39,7 @@ function testAdminTheme() { // Ensure that access to block admin page is denied when theme is disabled. $this->drupalGet('admin/structure/block/list/bartik'); - $this->assertResponse(403); + $this->assertResponse(404); // Enable admin theme and confirm that tab is accessible. theme_enable(array('bartik')); diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 4cf5780..a9a2b2c 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -2604,6 +2604,7 @@ function system_get_info($type, $name = NULL) { } } else { + // @todo Migrate theme info to ModuleInfo implementation. $list = system_list($type); foreach ($list as $shortname => $item) { if (!empty($item->status)) { @@ -2629,6 +2630,8 @@ function system_get_info($type, $name = NULL) { * returned. * * @see Drupal\Core\Utility\ModuleInfo + * + * @todo Merge this helper entirely into system_get_info()? */ function system_get_module_info($property) { static $info; @@ -2963,25 +2966,26 @@ function _system_default_theme_features() { /** * Get a list of available regions from a specified theme. * - * @param $theme_key - * The name of a theme. + * @param $theme + * A theme object, or the name of a theme. * @param $show * Possible values: REGIONS_ALL or REGIONS_VISIBLE. Visible excludes hidden * regions. * @return * An array of regions in the form $region['name'] = 'description'. */ -function system_region_list($theme_key, $show = REGIONS_ALL) { - $themes = list_themes(); - if (!isset($themes[$theme_key])) { - return array(); +function system_region_list($theme, $show = REGIONS_ALL) { + if (!is_object($theme)) { + $themes = list_themes(); + if (!isset($themes[$theme])) { + return array(); + } + $theme = $themes[$theme]; } - $list = array(); - $info = $themes[$theme_key]->info; // If requested, suppress hidden regions. See block_admin_display_form(). - foreach ($info['regions'] as $name => $label) { - if ($show == REGIONS_ALL || !isset($info['regions_hidden']) || !in_array($name, $info['regions_hidden'])) { + foreach ($theme->info['regions'] as $name => $label) { + if ($show == REGIONS_ALL || !isset($theme->info['regions_hidden']) || !in_array($name, $theme->info['regions_hidden'])) { $list[$name] = t($label); } }