t('Create content'), 'cache' => BLOCK_NO_CACHE, 'admin' => TRUE ); $blocks['theme'] = array( 'info' => t('Theme switcher'), 'cache' => BLOCK_CACHE_PER_ROLE, 'admin' => TRUE ); $blocks['account'] = array( 'info' => t('My Account'), 'cache' => BLOCK_NO_CACHE, 'admin' => TRUE ); if (module_exists('menu')) { $blocks['menu'] = array( 'info' => t('Administration menu'), 'cache' => BLOCK_CACHE_PER_ROLE, 'admin' => TRUE, ); } if (module_exists('devel')) { $blocks['devel'] = array( 'info' => t('Devel'), 'cache' => BLOCK_NO_CACHE, 'admin' => TRUE ); } return $blocks; case 'view': switch ($delta) { case 'create': $item = menu_get_item('node/add'); $links = system_admin_menu_block($item); if (!empty($links)) { $menu = array(); foreach ($links as $key => $link) { $menu[$key] = array('link' => $link, 'below' => FALSE); } return array( 'subject' => !empty($item['title']) ? $item['title'] : t('Create content'), 'content' => theme('admin_drilldown_menu_tree_output', $menu), ); } break; case 'theme': module_load_include('inc', 'admin', 'includes/admin.theme'); return admin_block_theme(); case 'account': return admin_account_block(); case 'menu': $item = menu_get_item('admin'); if ($item && $item['access']) { return array( 'subject' => !empty($item['title']) ? $item['title'] : t('Administer'), 'content' => theme('admin_drilldown_menu_tree_output', menu_tree_all_data('admin')), ); } break; case 'devel': module_load_include('inc', 'admin', 'includes/admin.devel'); return admin_block_devel(); } break; } } /** * Implement our own simplified block caching. Because the Drupal core block * caching system is so conservative (e.g. disabled when *any* node_access * module is enabled), we roll our own solution here. Note that except for * the introduction of a user 1 specific cache, the cid generated by this * function is compatible with those in Drupal core. */ function admin_block_get_cache_id($block) { global $theme, $base_root, $user; if ($block->cache != BLOCK_NO_CACHE) { $cid_parts = array(); // Start with common sub-patterns: block identification, theme, language. $cid_parts[] = $block->module; $cid_parts[] = $block->delta; $cid_parts[] = $theme; if (module_exists('locale')) { global $language; $cid_parts[] = $language->language; } // In addition to the Drupal core pattern, allow caching separately for u1. if ($user->uid == 1) { $cid_parts[] = "u.$user->uid"; } else if ($block->cache & BLOCK_CACHE_PER_ROLE) { $cid_parts[] = 'r.'. implode(',', array_keys($user->roles)); } elseif ($block->cache & BLOCK_CACHE_PER_USER) { $cid_parts[] = "u.$user->uid"; } if ($block->cache & BLOCK_CACHE_PER_PAGE) { $cid_parts[] = $base_root . request_uri(); } return implode(':', $cid_parts); } } /** * Implementation of hook_elements(). */ function admin_elements() { return array( 'admin_panes' => array('#value' => ''), ); } /** * Implementation of hook_menu_alter(). */ function admin_menu_alter(&$items) { // Move admin theme item under ours as a local task. $items['admin/settings/admin/theme'] = $items['admin/settings/admin']; $items['admin/settings/admin/theme']['type'] = MENU_LOCAL_TASK; $items['admin/settings/admin/theme']['weight'] = 10; // Generate our own admin settings page. $items['admin/settings/admin'] = $items['admin/settings/admin/settings'] = array( 'title' => 'Administration tools', 'description' => 'Settings for site administration tools.', 'page callback' => 'drupal_get_form', 'page arguments' => array('admin_settings_form'), 'access callback' => 'user_access', 'access arguments' => array('administer site configuration'), 'type' => MENU_NORMAL_ITEM, 'file' => 'admin.admin.inc', 'module' => 'admin', ); $items['admin/settings/admin/settings']['title'] = 'Settings'; $items['admin/settings/admin/settings']['type'] = MENU_DEFAULT_LOCAL_TASK; $items['admin/settings/admin/rebuild'] = array( 'title' => 'Rebuild', 'description' => 'Wipe and rebuild the administrative menu.', 'page callback' => 'drupal_get_form', 'page arguments' => array('admin_settings_rebuild'), 'access callback' => 'user_access', 'access arguments' => array('administer site configuration'), 'type' => MENU_LOCAL_TASK, 'file' => 'admin.admin.inc', 'module' => 'admin', 'weight' => 10, ); foreach ($items as $path => $item) { $item['type'] = isset($item['type']) ? $item['type'] : MENU_NORMAL_ITEM; // Move all admin/* items to admin menu links except local tasks, callbacks. $args = explode('/', $path); if ($path === 'admin' || (($item['type'] & MENU_NORMAL_ITEM) && $args && $args[0] === 'admin')) { $items[$path]['menu_name'] = 'admin'; } // Smarter access callback for poorly checked landing pages if (!empty($item['access arguments']) && !empty($item['page callback']) && $item['access arguments'] === array('access administration pages') && in_array($item['page callback'], array('system_admin_menu_block_page', 'system_settings_overview'))) { $items[$path]['access callback'] = 'admin_landing_page_access'; $items[$path]['access arguments'] = array($path); } } } /** * Menu access callback for admin landing pages. * * For a given landing page, grant access if the current user has access * to any of its child menu items. */ function admin_landing_page_access($path) { static $paths; if (!isset($paths[$path])) { $item = db_fetch_array(db_query("SELECT mlid, menu_name FROM {menu_links} ml WHERE ml.router_path = '%s' AND module = 'system'", $path)); $result = db_query(" SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type, m.description, ml.* FROM {menu_links} ml LEFT JOIN {menu_router} m ON ml.link_path = m.path WHERE ml.plid = %d AND ml.menu_name = '%s' AND hidden = 0", $item['mlid'], $item['menu_name']); $paths[$path] = FALSE; while ($item = db_fetch_array($result)) { _menu_link_translate($item); if ($item['access']) { $paths[$path] = TRUE; break; } } } return $paths[$path]; } /** * Implementation of hook_perm(). */ function admin_perm() { return array('use admin toolbar'); } /** * Implementation of hook_theme(). */ function admin_theme($cache, $type, $theme, $path) { $path = drupal_get_path('module', 'admin'); $items['admin_tab'] = array( 'arguments' => array('tab' => array(), 'class' => ''), 'path' => $path . '/theme', 'file' => 'theme.inc', ); $items['admin_toolbar'] = array( 'arguments' => array( 'blocks' => array(), 'position' => 'ne', 'layout' => 'horizontal', 'behavior' => 'df', ), 'template' => 'admin-toolbar', 'path' => $path . '/theme', 'file' => 'theme.inc', ); $items['admin_drilldown_menu_tree_output'] = array( 'arguments' => array('menu' => array()), 'path' => $path . '/theme', 'file' => 'theme.inc', ); $items['admin_drilldown_menu_tree'] = array( 'arguments' => array('menu' => array()), 'path' => $path . '/theme', 'file' => 'theme.inc', ); $items['admin_drilldown_menu_item'] = array( 'arguments' => array( 'link' => NULL, 'has_children' => NULL, 'menu' => '', 'in_active_trail' => FALSE, 'extra_class' => NULL, ), 'path' => $path . '/theme', 'file' => 'theme.inc', ); $items['admin_drilldown_menu_item_link'] = array( 'arguments' => array('item' => array()), 'path' => $path . '/theme', 'file' => 'theme.inc', ); $items['admin_panes'] = array( 'arguments' => array('element' => array()), 'template' => 'admin-panes', 'path' => $path . '/theme', 'file' => 'theme.inc', ); $items['admin_settings_form'] = array( 'arguments' => array('element' => array()), 'path' => $path, 'file' => 'admin.admin.inc', ); return $items; } /** * Implementation of hook_theme_registry_alter(). */ function admin_theme_registry_alter(&$theme_registry) { // Remove any existing instances of our pre page preprocessor. $position = array_search('admin_preprocess_pre_page', $theme_registry['page']['preprocess functions']); if ($position !== FALSE) { unset($theme_registry['page']['preprocess functions'][$position]); } // Add an additional page preprocess function prior to template_preprocess_page() // so that our blocks can include JS files as needed. $position = array_search('template_preprocess_page', $theme_registry['page']['preprocess functions']); if ($position !== FALSE) { array_splice($theme_registry['page']['preprocess functions'], $position, 0, 'admin_preprocess_pre_page'); } } /** * Get variable settings or fallback to defaults. */ function admin_get_settings($key = NULL) { static $settings; if (!isset($settings)) { // Try to gather what information we can from the cookie. // Note that this information should not be trusted in any // way for affecting *anything* but trivial changes to the site. $cookie = array(); if (isset($_REQUEST['DrupalAdminToolbar'])) { parse_str($_REQUEST['DrupalAdminToolbar'], $cookie); } $settings = variable_get('admin_toolbar', array()) + array( 'layout' => 'vertical', 'position' => 'nw', 'behavior' => 'df', 'blocks' => admin_get_default_blocks(), 'expanded' => isset($cookie['expanded']) ? check_plain($cookie['expanded']) : 0, 'active_tab' => isset($cookie['activeTab']) ? check_plain($cookie['activeTab']) : 0, ); // Ensure that if behavior is set to autohide the toolbar is collapsed. if ($settings['behavior'] === 'ah') { $settings['expanded'] = 0; } } if (isset($key)) { return isset($settings[$key]) ? $settings[$key] : FALSE; } return $settings; } /** * Get all blocks that have declared themselves visible in the admin toolbar by default. */ function admin_get_default_blocks($reset = FALSE) { static $defaults; if (!isset($defaults) || $reset) { $cache = cache_get('admin_default_blocks'); if ($cache && !$reset) { $defaults = $cache->data; } else { $defaults = array(); foreach (module_implements('block') as $module) { $module_blocks = module_invoke($module, 'block', 'list'); if ($module_blocks) { foreach ($module_blocks as $delta => $info) { if (isset($info['admin'])) { $defaults["{$module}-{$delta}"] = isset($info['cache']) ? $info['cache'] : BLOCK_NO_CACHE; } } } } cache_set('admin_default_blocks', $defaults); } } return $defaults; } /** * Set static cache for blocks enabled for the admin toolbar. */ function admin_set_admin_blocks($reset = FALSE) { static $blocks; if (!isset($blocks) || $reset) { $blocks = array(); if (user_access('use admin toolbar') && $enabled_blocks = admin_get_settings('blocks')) { foreach ($enabled_blocks as $bid => $cache) { $block = NULL; $split = explode('-', $bid, 2); if (count($split) === 2) { list($module, $delta) = $split; $block = new stdClass(); $block->module = $module; $block->delta = $delta; $block->cache = is_numeric($cache) ? $cache : BLOCK_NO_CACHE; $block->region = 'admin_toolbar'; // Fake the block region. } if (!empty($block)) { if ($_SERVER['REQUEST_METHOD'] == 'GET' && $cid = admin_block_get_cache_id($block)) { if ($cache = cache_get($cid, 'cache_block')) { $array = $cache->data; } else { $array = module_invoke($block->module, 'block', 'view', $block->delta); cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY); } } else { $array = module_invoke($block->module, 'block', 'view', $block->delta); } if (!empty($array['content'])) { foreach ($array as $k => $v) { $block->{$k} = $v; } if ($block->module === 'block') { global $theme; $block->subject = db_result(db_query("SELECT title FROM {blocks} WHERE module = 'block' AND delta = '%s'", $delta)); } // This is here simpy to trigger any preprocess functions that may // add javascript, etc. for this block. Note that the output is // thrown away. theme('block', $block); $blocks["{$module}-{$delta}"] = $block; } } } } } return $blocks; } /** * Get wrapper around admin blocks set. */ function admin_get_admin_blocks($reset = FALSE) { return admin_set_admin_blocks($reset); } /** * Preprocessor that runs *before* template_preprocess_page(). */ function admin_preprocess_pre_page(&$vars) { admin_set_admin_blocks(); if (user_access('use admin toolbar') && $trail = menu_get_active_trail()) { do { $last = array_pop($trail); } while (count($trail) && !($last['type'] & MENU_VISIBLE_IN_TREE)); if ($last) { drupal_add_js(array('activePath' => url($last['href'])), 'setting'); } } } /** * Implementation of hook_preprocess_page(). */ function admin_preprocess_page(&$vars) { if (!admin_suppress(FALSE) && $blocks = admin_get_admin_blocks()) { $position = admin_get_settings('position'); $layout = admin_get_settings('layout'); $behavior = admin_get_settings('behavior'); $class = admin_get_settings('expanded') ? 'admin-expanded' : ''; $vars['body_classes'] .= " admin-{$position} admin-{$layout} admin-{$behavior} {$class} "; } } /** * Implementation of hook_footer(). */ function admin_footer() { if (!admin_suppress(FALSE) && $blocks = admin_get_admin_blocks()) { $position = admin_get_settings('position'); $layout = admin_get_settings('layout'); $behavior = admin_get_settings('behavior'); $class = admin_get_settings('expanded') ? 'admin-expanded' : ''; return theme('admin_toolbar', $blocks, $position, $layout, $behavior); } } /** * Implementation of hook_suppress(). * * Suppress display of administration toolbar. * * This function should be called from within another module's page callback * preferably using module_invoke_all('suppress') when the menu should not be * displayed. This is useful for modules that implement popup pages or other * special pages where the menu would be distracting or break the layout. * * @param $set * Defaults to TRUE. If called before hook_footer(), the menu will not be * displayed. If FALSE is passed, the suppression state is returned. */ function admin_suppress($set = TRUE) { static $suppress = FALSE; if (!empty($set) && $suppress === FALSE) { $suppress = TRUE; } return $suppress; } /** * My Account block. */ function admin_account_block() { $block = array( 'subject' => t('My Account'), 'content' => '', ); global $user; if ($user->uid > 0) { $menu = array(); $menu[] = array( 'data' => l(t('View my account'), 'user/'. $user->uid), 'class' => 'leaf', ); $menu[] = array( 'data' => l(t('Edit my account'), 'user/'. $user->uid .'/edit'), 'class' => 'leaf', ); $menu[] = array( 'data' => l(t('Logout'), 'logout'), 'class' => 'leaf', ); $block['content'] = theme('item_list', $menu, NULL, 'ul', array('class' => 'menu')); } return $block; }