| [ PHPXref.com ] | [ Generated: Sun Jul 20 17:22:00 2008 ] | [ Drupal 5.0 ] |
| [ Index ] [ Variables ] [ Functions ] [ Classes ] [ Constants ] [ Statistics ] | ||
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: system.module,v 1.440.2.1 2007/01/15 12:04:14 unconed Exp $ 3 4 /** 5 * @file 6 * Configuration system that lets administrators modify the workings of the site. 7 */ 8 9 define('VERSION', '5.0'); 10 11 /** 12 * Implementation of hook_help(). 13 */ 14 function system_help($section) { 15 global $base_url; 16 17 switch ($section) { 18 case 'admin/help#system': 19 $output = '<p>'. t('The system module provides system-wide defaults such as running jobs at a particular time, and storing web pages to improve efficiency. The ability to run scheduled jobs makes administering the web site more usable, as administrators do not have to manually start jobs. The storing of web pages, or caching, allows the site to efficiently re-use web pages and improve web site performance. The settings module provides control over preferences, behaviours including visual and operational settings.') .'</p>'; 20 $output .= '<p>'. t('Some modules require regularly scheduled actions, such as cleaning up logfiles. Cron, which stands for chronograph, is a periodic command scheduler executing commands at intervals specified in seconds. It can be used to control the execution of daily, weekly and monthly jobs (or anything with a period measured in seconds). The aggregator module periodically updates feeds using cron. Ping periodically notifies services of new content on your site. Search periodically indexes the content on your site. Automating tasks is one of the best ways to keep a system running smoothly, and if most of your administration does not require your direct involvement, cron is an ideal solution. Cron can, if necessary, also be run manually.') .'</p>'; 21 $output .= '<p>'. t("There is a caching mechanism which stores dynamically generated web pages in a database. By caching a web page, the system module does not have to create the page each time someone wants to view it, instead it takes only one SQL query to display it, reducing response time and the server's load. Only pages requested by <em>anonymous</em> users are cached. In order to reduce server load and save bandwidth, the system module stores and sends cached pages compressed.") .'</p>'; 22 $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="@system">System page</a>.', array('@system' => 'http://drupal.org/handbook/modules/system/')) .'</p>'; 23 return $output; 24 case 'admin': 25 return '<p>'. t('Welcome to the administration section. Here you may control how your site functions.') .'</p>'; 26 case 'admin/by-module': 27 return '<p>'. t('This page shows you all available administration tasks for each module.') .'</p>'; 28 case 'admin/build/themes': 29 return '<p>'. t('Select which themes are available to your users and specify the default theme. To configure site-wide display settings, click the "configure" task above. Alternately, to override these settings in a specific theme, click the "configure" link for the corresponding theme. Note that different themes may have different regions available for rendering content like blocks. If you want consistency in what your users see, you may wish to enable only one theme.') .'</p>'; 30 case 'admin/build/themes/settings': 31 return '<p>'. t('These options control the default display settings for your entire site, across all themes. Unless they have been overridden by a specific theme, these settings will be used.') .'</p>'; 32 case 'admin/build/themes/settings/'. arg(3): 33 $reference = explode('.', arg(3), 2); 34 $theme = array_pop($reference); 35 return '<p>'. t('These options control the display settings for the <code>%template</code> theme. When your site is displayed using this theme, these settings will be used. By clicking "Reset to defaults," you can choose to use the <a href="@global">global settings</a> for this theme.', array('%template' => $theme, '@global' => url('admin/build/themes/settings'))) .'</p>'; 36 case 'admin/build/modules': 37 return t('<p>Modules are plugins for Drupal that extend its core functionality. Here you can select which modules are enabled. Click on the name of the module in the navigation menu for their individual configuration pages. Once a module is enabled, new <a href="@permissions">permissions</a> might be made available. Modules can automatically be temporarily disabled to reduce server load when your site becomes extremely busy by enabling the throttle.module and checking throttle. The auto-throttle functionality must be enabled on the <a href="@throttle">throttle configuration page</a> after having enabled the throttle module.</p> 38 <p>It is important that <a href="@update-php">update.php</a> is run every time a module is updated to a newer version.</p><p>You can find all administration tasks belonging to a particular module on the <a href="@by-module">administration by module page</a>.</p>', array('@permissions' => url('admin/user/access'), '@throttle' => url('admin/settings/throttle'), '@update-php' => $base_url .'/update.php', '@by-module' => url('admin/by-module'))); 39 case 'admin/build/modules/uninstall': 40 return '<p>'. t('The uninstall process removes all data related to a module. To uninstall a module, you must first disable it. Not all modules support this feature.') .'</p>'; 41 case 'admin/logs/status': 42 return '<p>'. t("Here you can find a short overview of your Drupal site's parameters as well as any problems detected with your installation. It is useful to copy/paste this information when you need support.") .'</p>'; 43 } 44 } 45 46 /** 47 * Implementation of hook_perm(). 48 */ 49 function system_perm() { 50 return array('administer site configuration', 'access administration pages', 'select different theme'); 51 } 52 53 /** 54 * Implementation of hook_elements(). 55 */ 56 function system_elements() { 57 // Top level form 58 $type['form'] = array('#method' => 'post', '#action' => request_uri()); 59 60 // Inputs 61 $type['checkbox'] = array('#input' => TRUE, '#return_value' => 1); 62 $type['submit'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => TRUE); 63 $type['button'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => FALSE); 64 $type['textfield'] = array('#input' => TRUE, '#size' => 60, '#maxlength' => 128, '#autocomplete_path' => FALSE); 65 $type['password'] = array('#input' => TRUE, '#size' => 60); 66 $type['password_confirm'] = array('#input' => TRUE, '#process' => array('expand_password_confirm' => array())); 67 $type['textarea'] = array('#input' => TRUE, '#cols' => 60, '#rows' => 5); 68 $type['radios'] = array('#input' => TRUE, '#process' => array('expand_radios' => array())); 69 $type['radio'] = array('#input' => TRUE); 70 $type['checkboxes'] = array('#input' => TRUE, '#process' => array('expand_checkboxes' => array()), '#tree' => TRUE); 71 $type['select'] = array('#input' => TRUE); 72 $type['weight'] = array('#input' => TRUE, '#delta' => 10, '#default_value' => 0, '#process' => array('process_weight' => array())); 73 $type['date'] = array('#input' => TRUE, '#process' => array('expand_date' => array()), '#validate' => array('date_validate' => array())); 74 $type['file'] = array('#input' => TRUE, '#size' => 60); 75 76 // Form structure 77 $type['item'] = array(); 78 $type['hidden'] = array('#input' => TRUE); 79 $type['value'] = array('#input' => TRUE); 80 $type['markup'] = array('#prefix' => '', '#suffix' => ''); 81 $type['fieldset'] = array('#collapsible' => FALSE, '#collapsed' => FALSE); 82 $type['token'] = array('#input'=> TRUE); 83 return $type; 84 } 85 86 /** 87 * Implementation of hook_menu(). 88 */ 89 function system_menu($may_cache) { 90 $items = array(); 91 92 if ($may_cache) { 93 $items[] = array('path' => 'system/files', 'title' => t('File download'), 94 'callback' => 'file_download', 95 'access' => TRUE, 96 'type' => MENU_CALLBACK); 97 98 $access = user_access('administer site configuration'); 99 100 $items[] = array('path' => 'admin', 'title' => t('Administer'), 101 'access' => user_access('access administration pages'), 102 'callback' => 'system_main_admin_page', 103 'weight' => 9); 104 $items[] = array('path' => 'admin/compact', 'title' => t('Compact mode'), 105 'access' => user_access('access administration pages'), 106 'callback' => 'system_admin_compact_page', 107 'type' => MENU_CALLBACK); 108 $items[] = array('path' => 'admin/by-task', 'title' => t('By task'), 109 'callback' => 'system_main_admin_page', 110 'type' => MENU_DEFAULT_LOCAL_TASK); 111 $items[] = array('path' => 'admin/by-module', 'title' => t('By module'), 112 'callback' => 'system_admin_by_module', 113 'type' => MENU_LOCAL_TASK, 114 'weight' => 2); 115 116 // menu items that are basically just menu blocks 117 $items[] = array( 118 'path' => 'admin/settings', 119 'title' => t('Site configuration'), 120 'description' => t('Adjust basic site configuration options.'), 121 'position' => 'right', 122 'weight' => -5, 123 'callback' => 'system_settings_overview', 124 'access' => $access); 125 126 $items[] = array('path' => 'admin/build', 127 'title' => t('Site building'), 128 'description' => t('Control how your site looks and feels.'), 129 'position' => 'right', 130 'weight' => -10, 131 'callback' => 'system_admin_menu_block_page', 132 'access' => $access); 133 134 $items[] = array( 135 'path' => 'admin/settings/admin', 136 'title' => t('Administration theme'), 137 'description' => t('Settings for how your administrative pages should look.'), 138 'position' => 'left', 139 'callback' => 'drupal_get_form', 140 'callback arguments' => array('system_admin_theme_settings'), 141 'block callback' => 'system_admin_theme_settings', 142 'access' => $access); 143 144 // Themes: 145 $items[] = array( 146 'path' => 'admin/build/themes', 147 'title' => t('Themes'), 148 'description' => t('Change which theme your site uses or allows users to set.'), 149 'callback' => 'drupal_get_form', 150 'callback arguments' => array('system_themes'), 151 'access' => $access); 152 153 $items[] = array( 154 'path' => 'admin/build/themes/select', 155 'title' => t('List'), 156 'description' => t('Select the default theme.'), 157 'callback' => 'drupal_get_form', 158 'callback arguments' => array('system_themes'), 159 'access' => $access, 160 'type' => MENU_DEFAULT_LOCAL_TASK, 161 'weight' => -1); 162 163 $items[] = array('path' => 'admin/build/themes/settings', 164 'title' => t('Configure'), 165 'callback' => 'drupal_get_form', 166 'callback arguments' => array('system_theme_settings'), 167 'access' => $access, 168 'type' => MENU_LOCAL_TASK); 169 170 // Theme configuration subtabs 171 $items[] = array('path' => 'admin/build/themes/settings/global', 'title' => t('Global settings'), 172 'callback' => 'drupal_get_form', 173 'callback arguments' => array('system_theme_settings'), 174 'access' => $access, 175 'type' => MENU_DEFAULT_LOCAL_TASK, 176 'weight' => -1); 177 178 foreach (list_themes() as $theme) { 179 if ($theme->status) { 180 $items[] = array('path' => 'admin/build/themes/settings/'. $theme->name, 'title' => $theme->name, 181 'callback' => 'drupal_get_form', 'callback arguments' => array('system_theme_settings', $theme->name), 182 'access' => $access, 'type' => MENU_LOCAL_TASK); 183 } 184 } 185 186 // Modules: 187 $items[] = array('path' => 'admin/build/modules', 188 'title' => t('Modules'), 189 'description' => t('Enable or disable add-on modules for your site.'), 190 'callback' => 'drupal_get_form', 191 'callback arguments' => array('system_modules'), 192 'access' => $access); 193 $items[] = array('path' => 'admin/build/modules/list', 194 'title' => t('List'), 195 'type' => MENU_DEFAULT_LOCAL_TASK, 196 'access' => $access); 197 $items[] = array('path' => 'admin/build/modules/list/confirm', 198 'title' => t('List'), 199 'callback' => 'drupal_get_form', 200 'callback arguments' => array('system_modules'), 201 'type' => MENU_CALLBACK, 202 'access' => $access); 203 $items[] = array('path' => 'admin/build/modules/uninstall', 204 'title' => t('Uninstall'), 205 'callback' => 'drupal_get_form', 206 'callback arguments' => array('system_modules_uninstall'), 207 'type' => MENU_LOCAL_TASK, 208 'access' => $access); 209 $items[] = array('path' => 'admin/build/modules/uninstall/confirm', 210 'title' => t('Uninstall'), 211 'callback' => 'drupal_get_form', 212 'callback arguments' => array('system_modules_uninstall'), 213 'type' => MENU_CALLBACK, 214 'access' => $access); 215 216 // Settings: 217 $items[] = array( 218 'path' => 'admin/settings/site-information', 219 'title' => t('Site information'), 220 'description' => t('Change basic site information, such as the site name, slogan, e-mail address, mission, front page and more.'), 221 'callback' => 'drupal_get_form', 222 'callback arguments' => array('system_site_information_settings')); 223 $items[] = array( 224 'path' => 'admin/settings/error-reporting', 225 'title' => t('Error reporting'), 226 'description' => t('Control how Drupal deals with errors including 403/404 errors as well as PHP error reporting.'), 227 'callback' => 'drupal_get_form', 228 'callback arguments' => array('system_error_reporting_settings')); 229 $items[] = array( 230 'path' => 'admin/settings/performance', 231 'title' => t('Performance'), 232 'description' => t('Enable or disable page caching for anonymous users, and enable or disable CSS preprocessor.'), 233 'callback' => 'drupal_get_form', 234 'callback arguments' => array('system_performance_settings')); 235 $items[] = array( 236 'path' => 'admin/settings/file-system', 237 'title' => t('File system'), 238 'description' => t('Tell Drupal where to store uploaded files and how they are accessed.'), 239 'callback' => 'drupal_get_form', 240 'callback arguments' => array('system_file_system_settings')); 241 $items[] = array( 242 'path' => 'admin/settings/image-toolkit', 243 'title' => t('Image toolkit'), 244 'description' => t('Choose which image toolkit to use if you have installed optional toolkits.'), 245 'callback' => 'drupal_get_form', 246 'callback arguments' => array('system_image_toolkit_settings')); 247 $items[] = array( 248 'path' => 'admin/content/rss-publishing', 249 'title' => t('RSS publishing'), 250 'description' => t('Configure the number of items per feed and whether feeds should be titles/teasers/full-text.'), 251 'callback' => 'drupal_get_form', 252 'callback arguments' => array('system_rss_feeds_settings')); 253 $items[] = array( 254 'path' => 'admin/settings/date-time', 255 'title' => t('Date and time'), 256 'description' => t("Settings for how Drupal displays date and time, as well as the system's default timezone."), 257 'callback' => 'drupal_get_form', 258 'callback arguments' => array('system_date_time_settings')); 259 $items[] = array( 260 'path' => 'admin/settings/site-maintenance', 261 'title' => t('Site maintenance'), 262 'description' => t('Take the site off-line for maintenance or bring it back online.'), 263 'callback' => 'drupal_get_form', 264 'callback arguments' => array('system_site_maintenance_settings')); 265 $items[] = array( 266 'path' => 'admin/settings/clean-urls', 267 'title' => t('Clean URLs'), 268 'description' => t('Enable or disable clean URLs for your site.'), 269 'callback' => 'drupal_get_form', 270 'callback arguments' => array('system_clean_url_settings')); 271 272 273 // Logs: 274 $items[] = array( 275 'path' => 'admin/logs', 276 'title' => t('Logs'), 277 'description' => t('View system logs and other status information.'), 278 'callback' => 'system_admin_menu_block_page', 279 'weight' => 5, 280 'position' => 'left'); 281 $items[] = array( 282 'path' => 'admin/logs/status', 283 'title' => t('Status report'), 284 'description' => t("Get a status report about your site's operation and any detected problems."), 285 'callback' => 'system_status', 286 'weight' => 10, 287 'access' => $access); 288 $items[] = array( 289 'path' => 'admin/logs/status/run-cron', 290 'title' => t('Run cron'), 291 'callback' => 'system_run_cron', 292 'type' => MENU_CALLBACK); 293 $items[] = array( 294 'path' => 'admin/logs/status/php', 295 'title' => t('PHP'), 296 'callback' => 'system_php', 297 'type' => MENU_CALLBACK); 298 $items[] = array( 299 'path' => 'admin/logs/status/sql', 300 'title' => t('SQL'), 301 'callback' => 'system_sql', 302 'type' => MENU_CALLBACK); 303 } 304 else { 305 /** 306 * Use the administrative theme if the user is looking at a page in the admin/* path. 307 */ 308 if (arg(0) == 'admin') { 309 global $custom_theme; 310 $custom_theme = variable_get('admin_theme', '0'); 311 drupal_add_css(drupal_get_path('module', 'system') .'/admin.css', 'module'); 312 } 313 314 // Add the CSS for this module. We put this in !$may_cache so it is only 315 // added once per request. 316 drupal_add_css(drupal_get_path('module', 'system') .'/defaults.css', 'module'); 317 drupal_add_css(drupal_get_path('module', 'system') .'/system.css', 'module'); 318 } 319 320 return $items; 321 } 322 323 /** 324 * Implementation of hook_user(). 325 * 326 * Allows users to individually set their theme and time zone. 327 */ 328 function system_user($type, $edit, &$user, $category = NULL) { 329 if ($type == 'form' && $category == 'account') { 330 $form['theme_select'] = system_theme_select_form(t('Selecting a different theme will change the look and feel of the site.'), $edit['theme'], 2); 331 332 if (variable_get('configurable_timezones', 1)) { 333 $zones = _system_zonelist(); 334 $form['timezone'] = array( 335 '#type'=>'fieldset', 336 '#title' => t('Locale settings'), 337 '#weight' => 6, 338 '#collapsible' => TRUE, 339 ); 340 $form['timezone']['timezone'] = array( 341 '#type' => 'select', 342 '#title' => t('Time zone'), 343 '#default_value' => strlen($edit['timezone']) ? $edit['timezone'] : variable_get('date_default_timezone', 0), 344 '#options' => $zones, 345 '#description' => t('Select your current local time. Dates and times throughout this site will be displayed using this time zone.'), 346 ); 347 } 348 349 return $form; 350 } 351 } 352 353 /** 354 * Provide the administration overview page. 355 */ 356 function system_main_admin_page($arg = NULL) { 357 // If we received an argument, they probably meant some other page. 358 // Let's 404 them since the menu system cannot be told we do not 359 // accept arguments. 360 if (isset($arg) && substr($arg, 0, 3) != 'by-') { 361 return drupal_not_found(); 362 } 363 364 // Check for status report errors. 365 if (system_status(TRUE)) { 366 drupal_set_message(t('One or more problems were detected with your Drupal installation. Check the <a href="@status">status report</a> for more information.', array('@status' => url('admin/logs/status'))), 'error'); 367 } 368 369 370 $menu = menu_get_item(NULL, 'admin'); 371 usort($menu['children'], '_menu_sort'); 372 foreach ($menu['children'] as $mid) { 373 $block = menu_get_item($mid); 374 if ($block['block callback'] && function_exists($block['block callback'])) { 375 $arguments = isset($block['block arguments']) ? $block['block arguments'] : array(); 376 $block['content'] .= call_user_func_array($block['block callback'], $arguments); 377 } 378 $block['content'] .= theme('admin_block_content', system_admin_menu_block($block)); 379 $blocks[] = $block; 380 } 381 382 return theme('admin_page', $blocks); 383 } 384 385 /** 386 * Provide a single block on the administration overview page. 387 */ 388 function system_admin_menu_block($block) { 389 $content = array(); 390 if (is_array($block['children'])) { 391 usort($block['children'], '_menu_sort'); 392 foreach ($block['children'] as $mid) { 393 $item = menu_get_item($mid); 394 if (($item['type'] & MENU_VISIBLE_IN_TREE) && _menu_item_is_accessible($mid)) { 395 $content[] = $item; 396 } 397 } 398 } 399 return $content; 400 } 401 402 /** 403 * Provide a single block from the administration menu as a page. 404 * This function is often a destination for these blocks. 405 * For example, 'admin/content/types' needs to have a destination to be valid 406 * in the Drupal menu system, but too much information there might be 407 * hidden, so we supply the contents of the block. 408 */ 409 function system_admin_menu_block_page() { 410 $menu = menu_get_item(NULL, $_GET['q']); 411 $content = system_admin_menu_block($menu); 412 413 $output = theme('admin_block_content', $content); 414 return $output; 415 } 416 417 function system_admin_compact_page($mode = 'off') { 418 global $user; 419 user_save($user, array('admin_compact_mode' => ($mode == 'on'))); 420 drupal_goto('admin'); 421 } 422 423 /** 424 * This function allows selection of the theme to show in administration sections. 425 */ 426 function system_admin_theme_settings() { 427 $themes = system_theme_data(); 428 ksort($themes); 429 $options[0] = t('System default'); 430 foreach ($themes as $theme) { 431 $options[$theme->name] = $theme->name; 432 } 433 434 $form['admin_theme'] = array( 435 '#type' => 'select', 436 '#options' => $options, 437 '#title' => t('Administration theme'), 438 '#description' => t('Choose which theme the administration pages should display in. If you choose "System default" the administration pages will use the same theme as the rest of the site.'), 439 '#default_value' => variable_get('admin_theme', '0'), 440 ); 441 442 // In order to give it our own submit, we have to give it the default submit 443 // too because the presence of a #submit will prevent the default #submit 444 // from being used. Also we want ours first. 445 $form['#submit']['system_admin_theme_submit'] = array(); 446 $form['#submit']['system_settings_form_submit'] = array(); 447 return system_settings_form($form); 448 } 449 450 451 function system_admin_theme_submit($form_id, $form_values) { 452 // If we're changing themes, make sure the theme has its blocks initialized. 453 if ($form_values['admin_theme'] != variable_get('admin_theme', '0')) { 454 $result = db_query("SELECT status FROM {blocks} WHERE theme = '%s'", $form_values['admin_theme']); 455 if (!db_num_rows($result)) { 456 system_initialize_theme_blocks($form_values['admin_theme']); 457 } 458 } 459 } 460 461 /* 462 * Returns a fieldset containing the theme select form. 463 * 464 * @param $description 465 * description of the fieldset 466 * @param $default_value 467 * default value of theme radios 468 * @param $weight 469 * weight of the fieldset 470 * @return 471 * a form array 472 */ 473 function system_theme_select_form($description = '', $default_value = '', $weight = 0) { 474 if (user_access('select different theme')) { 475 foreach (list_themes() as $theme) { 476 if ($theme->status) { 477 $enabled[] = $theme; 478 } 479 } 480 481 if (count($enabled) > 1) { 482 ksort($enabled); 483 484 $form['themes'] = array( 485 '#type' => 'fieldset', 486 '#title' => t('Theme configuration'), 487 '#description' => $description, 488 '#collapsible' => TRUE, 489 '#theme' => 'system_theme_select_form' 490 ); 491 492 foreach ($enabled as $info) { 493 // For the default theme, revert to an empty string so the user's theme updates when the site theme is changed. 494 $info->key = $info->name == variable_get('theme_default', 'garland') ? '' : $info->name; 495 496 $info->screenshot = dirname($info->filename) . '/screenshot.png'; 497 $screenshot = file_exists($info->screenshot) ? theme('image', $info->screenshot, t('Screenshot for %theme theme', array('%theme' => $info->name)), '', array('class' => 'screenshot'), FALSE) : t('no screenshot'); 498 499 $form['themes'][$info->key]['screenshot'] = array('#value' => $screenshot); 500 $form['themes'][$info->key]['description'] = array('#type' => 'item', '#title' => $info->name, '#value' => dirname($info->filename) . ($info->name == variable_get('theme_default', 'garland') ? '<br /> <em>'. t('(site default theme)') .'</em>' : '')); 501 $options[$info->key] = ''; 502 } 503 504 $form['themes']['theme'] = array('#type' => 'radios', '#options' => $options, '#default_value' => $default_value ? $default_value : ''); 505 $form['#weight'] = $weight; 506 return $form; 507 } 508 } 509 } 510 511 function theme_system_theme_select_form($form) { 512 foreach (element_children($form) as $key) { 513 $row = array(); 514 if (is_array($form[$key]['description'])) { 515 $row[] = drupal_render($form[$key]['screenshot']); 516 $row[] = drupal_render($form[$key]['description']); 517 $row[] = drupal_render($form['theme'][$key]); 518 } 519 $rows[] = $row; 520 } 521 522 $header = array(t('Screenshot'), t('Name'), t('Selected')); 523 $output = theme('table', $header, $rows); 524 return $output; 525 } 526 527 function _system_zonelist() { 528 $timestamp = time(); 529 $zonelist = array(-11, -10, -9.5, -9, -8, -7, -6, -5, -4, -3.5, -3, -2, -1, 0, 1, 2, 3, 3.5, 4, 5, 5.5, 5.75, 6, 6.5, 7, 8, 9, 9.5, 10, 10.5, 11, 11.5, 12, 12.75, 13, 14); 530 $zones = array(); 531 foreach ($zonelist as $offset) { 532 $zone = $offset * 3600; 533 $zones[$zone] = format_date($timestamp, 'custom', variable_get('date_format_long', 'l, F j, Y - H:i') . ' O', $zone); 534 } 535 return $zones; 536 } 537 538 function system_site_information_settings() { 539 $form['site_name'] = array( 540 '#type' => 'textfield', 541 '#title' => t('Name'), 542 '#default_value' => variable_get('site_name', 'Drupal'), 543 '#description' => t('The name of this web site.'), 544 '#required' => TRUE 545 ); 546 $form['site_mail'] = array( 547 '#type' => 'textfield', 548 '#title' => t('E-mail address'), 549 '#default_value' => variable_get('site_mail', ini_get('sendmail_from')), 550 '#description' => t('A valid e-mail address for this website, used by the auto-mailer during registration, new password requests, notifications, etc.') 551 ); 552 $form['site_slogan'] = array( 553 '#type' => 'textfield', 554 '#title' => t('Slogan'), 555 '#default_value' => variable_get('site_slogan', ''), 556 '#description' => t('The slogan of this website. Some themes display a slogan when available.') 557 ); 558 559 $form['site_mission'] = array( 560 '#type' => 'textarea', 561 '#title' => t('Mission'), 562 '#default_value' => variable_get('site_mission', ''), 563 '#description' => t('Your site\'s mission statement or focus.') 564 ); 565 $form['site_footer'] = array( 566 '#type' => 'textarea', 567 '#title' => t('Footer message'), 568 '#default_value' => variable_get('site_footer', ''), 569 '#description' => t('This text will be displayed at the bottom of each page. Useful for adding a copyright notice to your pages.') 570 ); 571 $form['anonymous'] = array( 572 '#type' => 'textfield', 573 '#title' => t('Anonymous user'), 574 '#default_value' => variable_get('anonymous', t('Anonymous')), 575 '#description' => t('The name used to indicate anonymous users.') 576 ); 577 $form['site_frontpage'] = array( 578 '#type' => 'textfield', 579 '#title' => t('Default front page'), 580 '#default_value' => variable_get('site_frontpage', 'node'), 581 '#size' => 40, 582 '#description' => t('The home page displays content from this relative URL. If unsure, specify "node".'), 583 '#field_prefix' => url(NULL, NULL, NULL, TRUE) . (variable_get('clean_url', 0) ? '' : '?q=') 584 ); 585 586 return system_settings_form($form); 587 } 588 589 function system_clean_url_settings() { 590 // We check for clean URL support using an image on the client side. 591 $form['clean_url'] = array( 592 '#type' => 'radios', 593 '#title' => t('Clean URLs'), 594 '#default_value' => variable_get('clean_url', 0), 595 '#options' => array(t('Disabled'), t('Enabled')), 596 '#description' => t('This option makes Drupal emit "clean" URLs (i.e. without <code>?q=</code> in the URL.)'), 597 ); 598 599 if (!variable_get('clean_url', 0)) { 600 if (strpos(request_uri(), '?q=') !== FALSE) { 601 $form['clean_url']['#description'] .= t(' Before enabling clean URLs, you must perform a test to determine if your server is properly configured. If you are able to see this page again after clicking the "Run the clean URL test" link, the test has succeeded and the radio buttons above will be available. If instead you are directed to a "Page not found" error, you will need to change the configuration of your server. The <a href="@handbook">handbook page on Clean URLs</a> has additional troubleshooting information. !run-test', array('@handbook' => 'http://drupal.org/node/15365', '!run-test' => '<a href ="'. base_path() . 'admin/settings/clean-urls">'. t('Run the clean URL test') .'</a>')); 602 $form['clean_url']['#disabled'] = TRUE; 603 } 604 else { 605 $form['clean_url']['#description'] .= t(' You have successfully demonstrated that clean URLs work on your server. You may enable/disable them as you wish.'); 606 $form['#collapsed'] = FALSE; 607 } 608 } 609 610 return system_settings_form($form); 611 } 612 613 function system_error_reporting_settings() { 614 615 $form['site_403'] = array( 616 '#type' => 'textfield', 617 '#title' => t('Default 403 (access denied) page'), 618 '#default_value' => variable_get('site_403', ''), 619 '#size' => 40, 620 '#description' => t('This page is displayed when the requested document is denied to the current user. If unsure, specify nothing.'), 621 '#field_prefix' => url(NULL, NULL, NULL, TRUE) . (variable_get('clean_url', 0) ? '' : '?q=') 622 ); 623 624 $form['site_404'] = array( 625 '#type' => 'textfield', 626 '#title' => t('Default 404 (not found) page'), 627 '#default_value' => variable_get('site_404', ''), 628 '#size' => 40, 629 '#description' => t('This page is displayed when no other content matches the requested document. If unsure, specify nothing.'), 630 '#field_prefix' => url(NULL, NULL, NULL, TRUE) . (variable_get('clean_url', 0) ? '' : '?q=') 631 ); 632 633 $form['error_level'] = array( 634 '#type' => 'select', '#title' => t('Error reporting'), '#default_value' => variable_get('error_level', 1), 635 '#options' => array(t('Write errors to the log'), t('Write errors to the log and to the screen')), 636 '#description' => t('Where Drupal, PHP and SQL errors are logged. On a production server it is recommended that errors are only written to the error log. On a test server it can be helpful to write logs to the screen.') 637 ); 638 639 $period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200), 'format_interval'); 640 $period['1000000000'] = t('Never'); 641 $form['watchdog_clear'] = array( 642 '#type' => 'select', 643 '#title' => t('Discard log entries older than'), 644 '#default_value' => variable_get('watchdog_clear', 604800), 645 '#options' => $period, 646 '#description' => t('The time log entries should be kept. Older entries will be automatically discarded. Requires crontab.') 647 ); 648 649 return system_settings_form($form); 650 } 651 652 function system_performance_settings() { 653 654 $description = '<p>'. t("The normal cache mode is suitable for most sites and does not cause any side effects. The aggressive cache mode causes Drupal to skip the loading (init) and unloading (exit) of enabled modules when serving a cached page. This results in an additional performance boost but can cause unwanted side effects.") .'</p>'; 655 656 $problem_modules = array_unique(array_merge(module_implements('init'), module_implements('exit'))); 657 sort($problem_modules); 658 659 if (count($problem_modules) > 0) { 660 $description .= '<p>'. t('<strong class="error">The following enabled modules are incompatible with aggressive mode caching and will not function properly: %modules</strong>', array('%modules' => implode(', ', $problem_modules))) .'.</p>'; 661 } 662 else { 663 $description .= '<p>'. t('<strong class="ok">Currently, all enabled modules are compatible with the aggressive caching policy.</strong> Please note, if you use aggressive caching and enable new modules, you will need to check this page again to ensure compatibility.') .'</p>'; 664 } 665 $form['page_cache'] = array( 666 '#type' => 'fieldset', 667 '#title' => t('Page cache'), 668 '#description' => t('Enabling the cache will offer a significant performance boost. Drupal can store and send compressed cached pages requested by <em>anonymous</em> users. By caching a web page, Drupal does not have to construct the page each time someone wants to view it.'), 669 ); 670 671 $form['page_cache']['cache'] = array( 672 '#type' => 'radios', 673 '#title' => t('Caching mode'), 674 '#default_value' => variable_get('cache', CACHE_DISABLED), 675 '#options' => array(CACHE_DISABLED => t('Disabled'), CACHE_NORMAL => t('Normal (recommended, no side effects)'), CACHE_AGGRESSIVE => t('Aggressive (experts only, possible side effects)')), 676 '#description' => $description 677 ); 678 679 $period = drupal_map_assoc(array(0, 60, 180, 300, 600, 900, 1800, 2700, 3600, 10800, 21600, 32400, 43200, 86400), 'format_interval'); 680 $period[0] = t('none'); 681 $form['page_cache']['cache_lifetime'] = array( 682 '#type' => 'select', 683 '#title' => t('Minimum cache lifetime'), 684 '#default_value' => variable_get('cache_lifetime', 0), 685 '#options' => $period, 686 '#description' => t('On high-traffic sites it can become necessary to enforce a minimum cache lifetime. The minimum cache lifetime is the minimum amount of time that will go by before the cache is emptied and recreated. A larger minimum cache lifetime offers better performance, but users will not see new content for a longer period of time.') 687 ); 688 689 $form['bandwidth_optimizations'] = array( 690 '#type' => 'fieldset', 691 '#title' => t('Bandwidth optimizations'), 692 '#description' => t('These options can help reduce both the size and number of requests made to your website. This can reduce the server load, the bandwidth used, and the average page loading time for your visitors.') 693 ); 694 695 $directory = file_directory_path(); 696 $is_writable = is_dir($directory) && is_writable($directory) && (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC); 697 $form['bandwidth_optimizations']['preprocess_css'] = array( 698 '#type' => 'radios', 699 '#title' => t('Aggregate and compress CSS files'), 700 '#default_value' => variable_get('preprocess_css', FALSE) && $is_writable, 701 '#disabled' => !$is_writable, 702 '#options' => array(t('Disabled'), t('Enabled')), 703 '#description' => t("Some Drupal modules include their own CSS files. When these modules are enabled, each module's CSS file adds an additional HTTP request to the page, which can increase the load time of each page. These HTTP requests can also slightly increase server load. It is recommended to only turn this option on when your site is in production, as it can interfere with theme development. This option is disabled if you have not set up your files directory, or if your download method is set to private."), 704 ); 705 706 $form['#submit']['system_settings_form_submit'] = array(); 707 $form['#submit']['drupal_clear_css_cache'] = array(); 708 709 return system_settings_form($form); 710 } 711 712 function system_file_system_settings() { 713 714 $form['file_directory_path'] = array( 715 '#type' => 'textfield', 716 '#title' => t('File system path'), 717 '#default_value' => file_directory_path(), 718 '#maxlength' => 255, 719 '#description' => t('A file system path where the files will be stored. This directory has to exist and be writable by Drupal. If the download method is set to public this directory has to be relative to the Drupal installation directory, and be accessible over the web. When download method is set to private this directory should not be accessible over the web. Changing this location after the site has been in use will cause problems so only change this setting on an existing site if you know what you are doing.'), 720 '#after_build' => array('system_check_directory'), 721 ); 722 723 $form['file_directory_temp'] = array( 724 '#type' => 'textfield', 725 '#title' => t('Temporary directory'), 726 '#default_value' => file_directory_temp(), 727 '#maxlength' => 255, 728 '#description' => t('Location where uploaded files will be kept during previews. Relative paths will be resolved relative to the Drupal installation directory.'), 729 '#after_build' => array('system_check_directory'), 730 ); 731 732 $form['file_downloads'] = array( 733 '#type' => 'radios', 734 '#title' => t('Download method'), 735 '#default_value' => variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC), 736 '#options' => array(FILE_DOWNLOADS_PUBLIC => t('Public - files are available using HTTP directly.'), FILE_DOWNLOADS_PRIVATE => t('Private - files are transferred by Drupal.')), 737 '#description' => t('If you want any sort of access control on the downloading of files, this needs to be set to <em>private</em>. You can change this at any time, however all download URLs will change and there may be unexpected problems so it is not recommended.') 738 ); 739 740 return system_settings_form($form); 741 } 742 743 function system_image_toolkit_settings() { 744 $toolkits_available = image_get_available_toolkits(); 745 if (count($toolkits_available) > 1) { 746 $form['image_toolkit'] = array( 747 '#type' => 'radios', 748 '#title' => t('Select an image processing toolkit'), 749 '#default_value' => variable_get('image_toolkit', image_get_toolkit()), 750 '#options' => $toolkits_available 751 ); 752 } 753 else { 754 $form['image_toolkit'] = array('#value' => '<p>'. t("No image toolkits found. Drupal will use PHP's built-in GD library for image handling.") .'</p>'); 755 } 756 $form['image_toolkit_settings'] = image_toolkit_invoke('settings'); 757 return system_settings_form($form); 758 } 759 760 function system_rss_feeds_settings() { 761 762 $form['feed_default_items'] = array( 763 '#type' => 'select', 764 '#title' => t('Number of items per feed'), 765 '#default_value' => variable_get('feed_default_items', 10), 766 '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30)), 767 '#description' => t('The default number of items to include in a feed.') 768 ); 769 $form['feed_item_length'] = array( 770 '#type' => 'select', 771 '#title' => t('Display of XML feed items'), 772 '#default_value' => variable_get('feed_item_length','teaser'), 773 '#options' => array('title' => t('Titles only'), 'teaser' => t('Titles plus teaser'), 'fulltext' => t('Full text')), 774 '#description' => t('Global setting for the length of XML feed items that are output by default.') 775 ); 776 777 return system_settings_form($form); 778 } 779 780 function system_date_time_settings() { 781 // Date settings: 782 $zones = _system_zonelist(); 783 784 // Date settings: possible date formats 785 $dateshort = array('Y-m-d H:i', 'm/d/Y - H:i', 'd/m/Y - H:i', 'Y/m/d - H:i', 786 'd.m.Y - H:i', 'm/d/Y - g:ia', 'd/m/Y - g:ia', 'Y/m/d - g:ia', 787 'M j Y - H:i', 'j M Y - H:i', 'Y M j - H:i', 788 'M j Y - g:ia', 'j M Y - g:ia', 'Y M j - g:ia'); 789 $datemedium = array('D, Y-m-d H:i', 'D, m/d/Y - H:i', 'D, d/m/Y - H:i', 790 'D, Y/m/d - H:i', 'F j, Y - H:i', 'j F, Y - H:i', 'Y, F j - H:i', 791 'D, m/d/Y - g:ia', 'D, d/m/Y - g:ia', 'D, Y/m/d - g:ia', 792 'F j, Y - g:ia', 'j F Y - g:ia', 'Y, F j - g:ia', 'j. F Y - G:i'); 793 $datelong = array('l, F j, Y - H:i', 'l, j F, Y - H:i', 'l, Y, F j - H:i', 794 'l, F j, Y - g:ia', 'l, j F Y - g:ia', 'l, Y, F j - g:ia', 'l, j. F Y - G:i'); 795 796 // Date settings: construct choices for user 797 foreach ($dateshort as $f) { 798 $dateshortchoices[$f] = format_date(time(), 'custom', $f); 799 } 800 foreach ($datemedium as $f) { 801 $datemediumchoices[$f] = format_date(time(), 'custom', $f); 802 } 803 foreach ($datelong as $f) { 804 $datelongchoices[$f] = format_date(time(), 'custom', $f); 805 } 806 807 $form['date_default_timezone'] = array( 808 '#type' => 'select', 809 '#title' => t('Default time zone'), 810 '#default_value' => variable_get('date_default_timezone', 0), 811 '#options' => $zones, 812 '#description' => t('Select the default site time zone.') 813 ); 814 815 $form['configurable_timezones'] = array( 816 '#type' => 'radios', 817 '#title' => t('Configurable time zones'), 818 '#default_value' => variable_get('configurable_timezones', 1), 819 '#options' => array(t('Disabled'), t('Enabled')), 820 '#description' => t('Enable or disable user-configurable time zones. When enabled, users can set their own time zone and dates will be updated accordingly.') 821 ); 822 823 $form['date_format_short'] = array( 824 '#type' => 'select', 825 '#title' => t('Short date format'), 826 '#default_value' => variable_get('date_format_short', $dateshort[1]), 827 '#options' => $dateshortchoices, 828 '#description' => t('The short format of date display.') 829 ); 830 831 $form['date_format_medium'] = array( 832 '#type' => 'select', 833 '#title' => t('Medium date format'), 834 '#default_value' => variable_get('date_format_medium', $datemedium[1]), 835 '#options' => $datemediumchoices, 836 '#description' => t('The medium sized date display.') 837 ); 838 839 $form['date_format_long'] = array( 840 '#type' => 'select', 841 '#title' => t('Long date format'), 842 '#default_value' => variable_get('date_format_long', $datelong[0]), 843 '#options' => $datelongchoices, 844 '#description' => t('Longer date format used for detailed display.') 845 ); 846 847 $form['date_first_day'] = array( 848 '#type' => 'select', 849 '#title' => t('First day of week'), 850 '#default_value' => variable_get('date_first_day', 0), 851 '#options' => array(0 => t('Sunday'), 1 => t('Monday'), 2 => t('Tuesday'), 3 => t('Wednesday'), 4 => t('Thursday'), 5 => t('Friday'), 6 => t('Saturday')), 852 '#description' => t('The first day of the week for calendar views.') 853 ); 854 855 return system_settings_form($form); 856 } 857 858 function system_site_maintenance_settings() { 859 860 $form['site_offline'] = array( 861 '#type' => 'radios', 862 '#title' => t('Site status'), 863 '#default_value' => variable_get('site_offline', 0), 864 '#options' => array(t('Online'), t('Off-line')), 865 '#description' => t('When set to "Online", all visitors will be able to browse your site normally. When set to "Off-line", only users with the "administer site configuration" permission will be able to access your site to perform maintenance; all other visitors will see the site off-line message configured below. Authorized users can log in during "Off-line" mode directly via the <a href="@user-login">user login</a> page.', array('@user-login' => url('user'))), 866 ); 867 868 $form['site_offline_message'] = array( 869 '#type' => 'textarea', 870 '#title' => t('Site off-line message'), 871 '#default_value' => variable_get('site_offline_message', t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')))), 872 '#description' => t('Message to show visitors when the site is in off-line mode.') 873 ); 874 875 return system_settings_form($form); 876 } 877 878 /** 879 * Checks the existence of the directory specified in $form_element. This 880 * function is called from the system_settings form to check both the 881 * file_directory_path and file_directory_temp directories. If validation 882 * fails, the form element is flagged with an error from within the 883 * file_check_directory function. 884 * 885 * @param $form_element 886 * The form element containing the name of the directory to check. 887 */ 888 function system_check_directory($form_element) { 889 file_check_directory($form_element['#value'], FILE_CREATE_DIRECTORY, $form_element['#parents'][0]); 890 return $form_element; 891 } 892 893 /** 894 * Retrieves the current status of an array of files in the system table. 895 */ 896 function system_get_files_database(&$files, $type) { 897 // Extract current files from database. 898 $result = db_query("SELECT filename, name, type, status, throttle, schema_version FROM {system} WHERE type = '%s'", $type); 899 while ($file = db_fetch_object($result)) { 900 if (isset($files[$file->name]) && is_object($files[$file->name])) { 901 $file->old_filename = $file->filename; 902 foreach ($file as $key => $value) { 903 if (!isset($files[$file->name]) || !isset($files[$file->name]->$key)) { 904 $files[$file->name]->$key = $value; 905 } 906 } 907 } 908 } 909 } 910 911 /** 912 * Collect data about all currently available themes 913 */ 914 function system_theme_data() { 915 include_once './includes/install.inc'; 916 917 // Find themes 918 $themes = drupal_system_listing('\.theme$', 'themes'); 919 920 // Find theme engines 921 $engines = drupal_system_listing('\.engine$', 'themes/engines'); 922 923 // can't iterate over array itself as it uses a copy of the array items 924 foreach (array_keys($themes) as $key) { 925 drupal_get_filename('theme', $themes[$key]->name, $themes[$key]->filename); 926 drupal_load('theme', $themes[$key]->name); 927 $themes[$key]->owner = $themes[$key]->filename; 928 $themes[$key]->prefix = $key; 929 } 930 931 // Remove all theme engines from the system table 932 db_query("DELETE FROM {system} WHERE type = 'theme_engine'"); 933 934 foreach ($engines as $engine) { 935 // Insert theme engine into system table 936 drupal_get_filename('theme_engine', $engine->name, $engine->filename); 937 drupal_load('theme_engine', $engine->name); 938 db_query("INSERT INTO {system} (name, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', %d, %d, %d)", $engine->name, 'theme_engine', $engine->filename, 1, 0, 0); 939 940 // Add templates to the site listing 941 foreach (call_user_func($engine->name . '_templates') as $template) { 942 // Do not double-insert templates with theme files in their directory, 943 // but do register their engine data. 944 if (array_key_exists($template->name, $themes)) { 945 $themes[$template->name]->template = TRUE; 946 $themes[$template->name]->owner = $engine->filename; 947 $themes[$template->name]->prefix = $engine->name; 948 } 949 else { 950 $template->template = TRUE; 951 $template->name = basename(dirname($template->filename)); 952 $template->owner = $engine->filename; 953 $template->prefix = $engine->name; 954 955 $themes[$template->name] = $template; 956 } 957 } 958 } 959 960 // Find styles in each theme's directory. 961 foreach ($themes as $theme) { 962 foreach (file_scan_directory(dirname($theme->filename), 'style.css$') as $style) { 963 $style->style = TRUE; 964 $style->template = isset($theme->template) ? $theme->template : FALSE; 965 $style->name = basename(dirname($style->filename)); 966 $style->owner = $theme->filename; 967 $style->prefix = $theme->template ? $theme->prefix : $theme->name; 968 // do not double-insert styles with theme files in their directory 969 if (array_key_exists($style->name, $themes)) { 970 continue; 971 } 972 $themes[$style->name] = $style; 973 } 974 } 975 976 // Extract current files from database. 977 system_get_files_database($themes, 'theme'); 978 979 db_query("DELETE FROM {system} WHERE type = 'theme'"); 980 981 foreach ($themes as $theme) { 982 db_query("INSERT INTO {system} (name, description, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', %d, %d, %d)", $theme->name, $theme->owner, 'theme', $theme->filename, $theme->status, 0, 0); 983 } 984 985 return $themes; 986 } 987 988 /** 989 * Get a list of available regions from a specified theme. 990 * 991 * @param $theme_key 992 * The name of a theme. 993 * @return 994 * An array of regions in the form $region['name'] = 'description'. 995 */ 996 function system_region_list($theme_key) { 997 static $list = array(); 998 999 if (!array_key_exists($theme_key, $list)) { 1000 $theme = db_fetch_object(db_query("SELECT * FROM {system} WHERE type = 'theme' AND name = '%s'", $theme_key)); 1001 1002 // Stylesheets can't have regions; use its theme. 1003 if (strpos($theme->filename, '.css')) { 1004 return system_region_list(basename(dirname($theme->description))); 1005 } 1006 1007 // If this is a custom theme, load it in before moving on. 1008 if (file_exists($file = dirname($theme->filename) .'/' . $theme_key . '.theme')) { 1009 include_once "./$file"; 1010 } 1011 1012 $regions = array(); 1013 1014 // This theme has defined its own regions. 1015 if (function_exists($theme_key . '_regions')) { 1016 $regions = call_user_func($theme_key . '_regions'); 1017 } 1018 // File is an engine; include its regions. 1019 else if (strpos($theme->description, '.engine')) { 1020 include_once './' . $theme->description; 1021 $theme_engine = basename($theme->description, '.engine'); 1022 $regions = function_exists($theme_engine . '_regions') ? call_user_func($theme_engine . '_regions') : array(); 1023 } 1024 1025 $list[$theme_key] = $regions; 1026 } 1027 1028 return $list[$theme_key]; 1029 } 1030 1031 /** 1032 * Get the name of the default region for a given theme. 1033 * 1034 * @param $theme 1035 * The name of a theme. 1036 * @return 1037 * A string that is the region name. 1038 */ 1039 function system_default_region($theme) { 1040 $regions = array_keys(system_region_list($theme)); 1041 return $regions[0]; 1042 } 1043 1044 /** 1045 * Assign an initial, default set of blocks for a theme. 1046 * 1047 * This function is called the first time a new theme is enabled. The new theme 1048 * gets a copy of the default theme's blocks, with the difference that if a 1049 * particular region isn't available in the new theme, the block is assigned 1050 * to the new theme's default region. 1051 * 1052 * @param $theme 1053 * The name of a theme. 1054 */ 1055 function system_initialize_theme_blocks($theme) { 1056 // Initialize theme's blocks if none already registered. 1057 if (!(db_num_rows(db_query("SELECT module FROM {blocks} WHERE theme = '%s'", $theme)))) { 1058 $default_theme = variable_get('theme_default', 'garland'); 1059 $regions = system_region_list($theme); 1060 $result = db_query("SELECT * FROM {blocks} WHERE theme = '%s'", $default_theme); 1061 while ($block = db_fetch_array($result)) { 1062 // If the region isn't supported by the theme, assign the block to the theme's default region. 1063 if (!array_key_exists($block['region'], $regions)) { 1064 $block['region'] = system_default_region($theme); 1065 } 1066 db_query("INSERT INTO {blocks} (module, delta, theme, status, weight, region, visibility, pages, custom, throttle) VALUES ('%s', '%s', '%s', %d, %d, '%s', %d, '%s', %d, %d)", 1067 $block['module'], $block['delta'], $theme, $block['status'], $block['weight'], $block['region'], $block['visibility'], $block['pages'], $block['custom'], $block['throttle']); 1068 } 1069 } 1070 } 1071 1072 /** 1073 * Add default buttons to a form and set its prefix 1074 */ 1075 function system_settings_form($form) { 1076 $form['buttons']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration') ); 1077 $form['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset to defaults') ); 1078 1079 if (!empty($_POST) && form_get_errors()) { 1080 drupal_set_message(t('The settings have not been saved because of the errors.'), 'error'); 1081 } 1082 $form['#base'] = 'system_settings_form'; 1083 return $form; 1084 } 1085 1086 function system_theme_settings_submit($form_id, $form_values) { 1087 $op = isset($_POST['op']) ? $_POST['op'] : ''; 1088 $key = $form_values['var']; 1089 1090 // Exclude unnecessary elements. 1091 unset($form_values['var'], $form_values['submit'], $form_values['reset'], $form_values['form_id']); 1092 1093 if ($op == t('Reset to defaults')) { 1094 variable_del($key); 1095 drupal_set_message(t('The configuration options have been reset to their default values.')); 1096 } 1097 else { 1098 variable_set($key, $form_values); 1099 drupal_set_message(t('The configuration options have been saved.')); 1100 } 1101 1102 cache_clear_all(); 1103 } 1104 1105 /** 1106 * Execute the system_settings_form. 1107 * 1108 * If you want node type configure style handling of your checkboxes, 1109 * add an array_filter value to your form. 1110 * 1111 */ 1112 function system_settings_form_submit($form_id, $form_values) { 1113 $op = isset($form_values['op']) ? $form_values['op'] : ''; 1114 1115 // Exclude unnecessary elements. 1116 unset($form_values['submit'], $form_values['reset'], $form_values['form_id'], $form_values['op'], $form_values['form_token']); 1117 1118 foreach ($form_values as $key => $value) { 1119 if ($op == t('Reset to defaults')) { 1120 variable_del($key); 1121 } 1122 else { 1123 if (is_array($value) && isset($form_values['array_filter'])) { 1124 $value = array_keys(array_filter($value)); 1125 } 1126 variable_set($key, $value); 1127 } 1128 } 1129 if ($op == t('Reset to defaults')) { 1130 drupal_set_message(t('The configuration options have been reset to their default values.')); 1131 } 1132 else { 1133 drupal_set_message(t('The configuration options have been saved.')); 1134 } 1135 1136 menu_rebuild(); 1137 } 1138 1139 /** 1140 * Menu callback; displays a listing of all themes. 1141 */ 1142 function system_themes() { 1143 1144 drupal_clear_css_cache(); 1145 $themes = system_theme_data(); 1146 ksort($themes); 1147 1148 foreach ($themes as $info) { 1149 $info->screenshot = dirname($info->filename) . '/screenshot.png'; 1150 $screenshot = file_exists($info->screenshot) ? theme('image', $info->screenshot, t('Screenshot for %theme theme', array('%theme' => $info->name)), '', array('class' => 'screenshot'), FALSE) : t('no screenshot'); 1151 1152 $form[$info->name]['screenshot'] = array('#value' => $screenshot); 1153 $form[$info->name]['description'] = array('#type' => 'item', '#title' => $info->name, '#value' => dirname($info->filename)); 1154 $options[$info->name] = ''; 1155 if ($info->status) { 1156 $status[] = $info->name; 1157 } 1158 if ($info->status && (function_exists($info->prefix . '_settings') || function_exists($info->prefix . '_features'))) { 1159 $form[$info->name]['operations'] = array('#value' => l(t('configure'), 'admin/build/themes/settings/' . $info->name) ); 1160 } 1161 else { 1162 // Dummy element for drupal_render. Cleaner than adding a check in the theme function. 1163 $form[$info->name]['operations'] = array(); 1164 } 1165 } 1166 1167 $form['status'] = array('#type' => 'checkboxes', '#options' => $options, '#default_value' => $status); 1168 $form['theme_default'] = array('#type' => 'radios', '#options' => $options, '#default_value' => variable_get('theme_default', 'garland')); 1169 $form['buttons']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration') ); 1170 $form['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset to defaults') ); 1171 1172 return $form; 1173 } 1174 1175 function theme_system_themes($form) { 1176 foreach (element_children($form) as $key) { 1177 $row = array(); 1178 if (is_array($form[$key]['description'])) { 1179 $row[] = drupal_render($form[$key]['screenshot']); 1180 $row[] = drupal_render($form[$key]['description']); 1181 $row[] = array('data' => drupal_render($form['status'][$key]), 'align' => 'center'); 1182 if ($form['theme_default']) { 1183 $row[] = array('data' => drupal_render($form['theme_default'][$key]), 'align' => 'center'); 1184 $row[] = array('data' => drupal_render($form[$key]['operations']), 'align' => 'center'); 1185 } 1186 } 1187 $rows[] = $row; 1188 } 1189 1190 $header = array(t('Screenshot'), t('Name'), t('Enabled'), t('Default'), t('Operations')); 1191 $output = theme('table', $header, $rows); 1192 $output .= drupal_render($form); 1193 return $output; 1194 } 1195 1196 1197 function system_themes_submit($form_id, $form_values) { 1198 1199 db_query("UPDATE {system} SET status = 0 WHERE type = 'theme'"); 1200 1201 if ($form_values['op'] == t('Save configuration')) { 1202 if (is_array($form_values['status'])) { 1203 foreach ($form_values['status'] as $key => $choice) { 1204 // Always enable the default theme, despite its status checkbox being checked: 1205 if ($choice || $form_values['theme_default'] == $key) { 1206 system_initialize_theme_blocks($key); 1207 db_query("UPDATE {system} SET status = 1 WHERE type = 'theme' and name = '%s'", $key); 1208 } 1209 } 1210 } 1211 if (($admin_theme = variable_get('admin_theme', '0')) != '0' && $admin_theme != $form_values['theme_default']) { 1212 drupal_set_message(t('Please note that the <a href="!admin_theme_page">administration theme</a> is still set to the %admin_theme theme; consequently, the theme on this page remains unchanged. All non-administrative sections of the site, however, will show the selected %selected_theme theme by default.', array( 1213 '!admin_theme_page' => url('admin/settings/admin'), 1214 '%admin_theme' => $admin_theme, 1215 '%selected_theme' => $form_values['theme_default'], 1216 ))); 1217 } 1218 variable_set('theme_default', $form_values['theme_default']); 1219 } 1220 else { 1221 variable_del('theme_default'); 1222 db_query("UPDATE {system} SET status = 1 WHERE type = 'theme' AND name = 'garland'"); 1223 } 1224 1225 menu_rebuild(); 1226 drupal_set_message(t('The configuration options have been saved.')); 1227 return 'admin/build/themes'; 1228 } 1229 1230 /** 1231 * Menu callback; provides module enable/disable interface. 1232 * 1233 * Modules can be enabled or disabled and set for throttling if the throttle module is enabled. 1234 * The list of modules gets populated by module.info files, which contain each module's name, 1235 * description and dependencies. 1236 * @sa _module_parse_info_file for information on module.info descriptors. 1237 * 1238 * Dependency checking is performed to ensure that a module cannot be enabled if the module has 1239 * disabled dependencies and also to ensure that the module cannot be disabled if the module has 1240 * enabled dependents. 1241 * 1242 * @return 1243 * The form array. 1244 */ 1245 function system_modules($form_values = NULL) { 1246 // Get current list of modules. 1247 $files = module_rebuild_cache(); 1248 if ($confirm_form = system_modules_confirm_form($files, $form_values)) { 1249 return $confirm_form; 1250 } 1251 1252 // Store module list for validation callback. 1253 $form['validation_modules'] = array('#type' => 'value', '#value' => $files); 1254 1255 // Create storage for disabled modules as browser will disable checkboxes. 1256 $form['disabled_modules'] = array('#type' => 'value', '#value' => array()); 1257 1258 // Array for disabling checkboxes in callback system_module_disable. 1259 $disabled = array(); 1260 // Traverse the files retrieved and build the form. 1261 foreach ($files as $filename => $file) { 1262 $form['name'][$filename] = array('#value' => $file->info['name']); 1263 $form['version'][$filename] = array('#value' => $file->info['version']); 1264 $form['description'][$filename] = array('#value' => t($file->info['description'])); 1265 $options[$filename] = ''; 1266 if ($file->status) { 1267 $status[] = $file->name; 1268 } 1269 if ($file->throttle) { 1270 $throttle[] = $file->name; 1271 } 1272 1273 $dependencies = array(); 1274 // Check for missing dependencies. 1275 if (is_array($file->info['dependencies'])) { 1276 foreach ($file->info['dependencies'] as $dependency) { 1277 if (!isset($files[$dependency]) || !$files[$dependency]->status) { 1278 if (isset($files[$dependency])) { 1279 $dependencies[] = $files[$dependency]->info['name'] . t(' (<span class="admin-disabled">disabled</span>)'); 1280 } 1281 else { 1282 $dependencies[] = drupal_ucfirst($dependency) . t(' (<span class="admin-missing">missing</span>)'); 1283 $disabled[] = $filename; 1284 $form['disabled_modules']['#value'][$filename] = FALSE; 1285 } 1286 } 1287 else { 1288 $dependencies[] = $files[$dependency]->info['name'] . t(' (<span class="admin-enabled">enabled</span>)'); 1289 } 1290 } 1291 1292 // Add text for dependencies. 1293 if (!empty($dependencies)) { 1294 $form['description'][$filename]['dependencies'] = array( 1295 '#value' => t('Depends on: !dependencies', array('!dependencies' => implode(', ', $dependencies))), 1296 '#prefix' => '<div class="admin-dependencies">', 1297 '#suffix' => '</div>', 1298 ); 1299 } 1300 } 1301 1302 // Mark dependents disabled so user can not remove modules being depended on. 1303 $dependents = array(); 1304 if (is_array($file->info['dependents'])) { 1305 foreach ($file->info['dependents'] as $dependent) { 1306 if ($files[$dependent]->status == 1) { 1307 $dependents[] = $files[$dependent]->info['name'] . t(' (<span class="admin-enabled">enabled</span>)'); 1308 $disabled[] = $filename; 1309 $form['disabled_modules']['#value'][$filename] = TRUE; 1310 } 1311 else { 1312 $dependents[] = $files[$dependent]->info['name'] . t(' (<span class="admin-disabled">disabled</span>)'); 1313 } 1314 } 1315 } 1316 1317 // Add text for enabled dependents. 1318 if (!empty($dependents)){ 1319 $form['description'][$filename]['required'] = array( 1320 '#value' => t('Required by: !required', array('!required' => implode(', ', $dependents))), 1321 '#prefix' => '<div class="admin-required">', 1322 '#suffix' => '</div>', 1323 ); 1324 } 1325 } 1326 1327 // Merge in required modules. 1328 $modules_required = array('block', 'filter', 'node', 'system', 'user', 'watchdog'); 1329 foreach ($modules_required as $required) { 1330 $disabled[] = $required; 1331 $form['disabled_modules']['#value'][$required] = TRUE; 1332 } 1333 1334 // Handle status checkboxes, including overriding 1335 // the generated checkboxes for required modules. 1336 $form['status'] = array( 1337 '#type' => 'checkboxes', 1338 '#default_value' => $status, 1339 '#options' => $options, 1340 '#process' => array( 1341 'expand_checkboxes' => array(), 1342 'system_modules_disable' => array($disabled), 1343 ), 1344 ); 1345 1346 // Handle throttle checkboxes, including overriding the 1347 // generated checkboxes for required modules. 1348 if (module_exists('throttle')) { 1349 $form['throttle'] = array( 1350 '#type' => 'checkboxes', 1351 '#default_value' => $throttle, 1352 '#options' => $options, 1353 '#process' => array( 1354 'expand_checkboxes' => array(), 1355 'system_modules_disable' => array(array_merge($modules_required, array('throttle'))), 1356 ), 1357 ); 1358 } 1359 1360 $form['buttons']['submit'] = array( 1361 '#type' => 'submit', 1362 '#value' => t('Save configuration'), 1363 ); 1364 $form['#multistep'] = TRUE; 1365 $form['#action'] = url('admin/build/modules/list/confirm'); 1366 1367 return $form; 1368 } 1369 1370 /** 1371 * Form process callback function to disable check boxes. 1372 */ 1373 function system_modules_disable($form, $edit, $disabled) { 1374 foreach ($disabled as $key) { 1375 $form[$key]['#attributes']['disabled'] = 'disabled'; 1376 } 1377 return $form; 1378 } 1379 1380 function system_modules_confirm_form($modules, $form_values = array()) { 1381 $form = array(); 1382 $items = array(); 1383 1384 // Check values for submitted dependency errors. 1385 if ($dependencies = system_module_build_dependencies($modules, $form_values)) { 1386 // preserve the already switched on modules 1387 foreach ($modules as $name => $module) { 1388 if ($module->status) { 1389 $form['status'][$name] = array('#type' => 'hidden', '#value' => 1); 1390 } 1391 } 1392 1393 $form['validation_modules'] = array('#type' => 'value', '#value' => $modules); 1394 $form['status']['#tree'] = TRUE; 1395 foreach ($dependencies as $name => $missing_dependencies) { 1396 $form['status'][$name] = array('#type' => 'hidden', '#value' => 1); 1397 foreach ($missing_dependencies as $k => $dependency) { 1398 $form['status'][$dependency] = array('#type' => 'hidden', '#value' => 1); 1399 $info = $modules[$dependency]->info; 1400 $missing_dependencies[$k] = $info['name'] ? $info['name'] : drupal_ucfirst($dependency); 1401 } 1402 $t_argument = array( 1403 '%module' => $modules[$name]->info['name'], 1404 '%dependencies' => implode(', ', $missing_dependencies), 1405 ); 1406 $items[] = strtr(format_plural(count($missing_dependencies), 'You must enable the %dependencies module to install %module.', 'You must enable the %dependencies modules to install %module.'), $t_argument); 1407 } 1408 $form['text'] = array('#value' => theme('item_list', $items)); 1409 } 1410 1411 if ($form) { 1412 // Set some default form values 1413 $form = confirm_form( 1414 $form, 1415 t('Some required modules must be enabled'), 1416 'admin/build/modules', 1417 t('Would you like to continue with enabling the above?'), 1418 t('Continue'), 1419 t('Cancel')); 1420 return $form; 1421 } 1422 } 1423 1424 function system_module_build_dependencies($modules, $form_values) { 1425 static $dependencies; 1426 1427 if (!isset($dependencies) && isset($form_values)) { 1428 $dependencies = array(); 1429 foreach ($modules as $name => $module) { 1430 // If the module is disabled, will be switched on and it has dependencies. 1431 if (!$module->status && $form_values['status'][$name] && isset($module->info['dependencies'])) { 1432 foreach ($module->info['dependencies'] as $dependency) { 1433 if (!$form_values['status'][$dependency] && isset($modules[$dependency])) { 1434 if (!isset($dependencies[$name])) { 1435 $dependencies[$name] = array(); 1436 } 1437 $dependencies[$name][] = $dependency; 1438 } 1439 } 1440 } 1441 } 1442 } 1443 return $dependencies; 1444 } 1445 1446 /** 1447 * Submit callback; handles modules form submission. 1448 */ 1449 function system_modules_submit($form_id, $form_values) { 1450 include_once './includes/install.inc'; 1451 $new_modules = array(); 1452 1453 // Merge in disabled active modules since they should be enabled. 1454 // They don't appear because disabled checkboxes are not submitted 1455 // by browsers. 1456 $form_values['status'] = array_merge($form_values['status'], $form_values['disabled_modules']); 1457 1458 // Check values for dependency that we can't install. 1459 if ($dependencies = system_module_build_dependencies($form_values['validation_modules'], $form_values)) { 1460 // These are the modules that depend on existing modules. 1461 foreach (array_keys($dependencies) as $name) { 1462 $form_values['status'][$name] = 0; 1463 } 1464 } 1465 1466 $enable_modules = array(); 1467 $disable_modules = array(); 1468 foreach ($form_values['status'] as $key => $choice) { 1469 if ($choice) { 1470 if (drupal_get_installed_schema_version($key) == SCHEMA_UNINSTALLED) { 1471 $new_modules[] = $key; 1472 } 1473 else { 1474 $enable_modules[] = $key; 1475 } 1476 } 1477 else { 1478 $disable_modules[] = $key; 1479 } 1480 } 1481 1482 $old_module_list = module_list(); 1483 1484 if (!empty($enable_modules)) { 1485 module_enable($enable_modules); 1486 } 1487 if (!empty($disable_modules)) { 1488 module_disable($disable_modules); 1489 } 1490 1491 // Install new modules. 1492 foreach ($new_modules as $key => $module) { 1493 if (!drupal_check_module($module)) { 1494 unset($new_modules[$key]); 1495 } 1496 } 1497 drupal_install_modules($new_modules); 1498 1499 $current_module_list = module_list(TRUE, FALSE); 1500 1501 if (is_array($form_values['throttle'])) { 1502 foreach ($form_values['throttle'] as $key => $choice) { 1503 db_query("UPDATE {system} SET throttle = %d WHERE type = 'module' and name = '%s'", $choice ? 1 : 0, $key); 1504 } 1505 } 1506 1507 if ($old_module_list != $current_module_list) { 1508 menu_rebuild(); 1509 node_types_rebuild(); 1510 drupal_set_message(t('The configuration options have been saved.')); 1511 } 1512 1513 // If there where unmet dependencies and they haven't confirmed don't redirect. 1514 if ($dependencies && !isset($form_values['confirm'])) { 1515 return FALSE; 1516 } 1517 1518 drupal_clear_css_cache(); 1519 1520 return 'admin/build/modules'; 1521 } 1522 1523 /** 1524 * Theme call back for the modules form. 1525 */ 1526 function theme_system_modules($form) { 1527 if (isset($form['confirm'])) { 1528 return drupal_render($form); 1529 } 1530 1531 // Individual table headers. 1532 $header = array(t('Enabled')); 1533 if (module_exists('throttle')) { 1534 $header[] = t('Throttle'); 1535 } 1536 $header[] = t('Name'); 1537 $header[] = t('Version'); 1538 $header[] = t('Description'); 1539 1540 // Pull package information from module list and start grouping modules. 1541 $modules = $form['validation_modules']['#value']; 1542 foreach ($modules as $module) { 1543 if (!isset($module->info['package']) || !$module->info['package']) { 1544 $module->info['package'] = 'Other'; 1545 } 1546 $packages[$module->info['package']][$module->name] = $module->info; 1547 } 1548 ksort($packages); 1549 1550 // Display packages. 1551 $output = ''; 1552 foreach ($packages as $package => $modules) { 1553 $rows = array(); 1554 foreach ($modules as $key => $module) { 1555 $row = array(); 1556 $row[] = array('data' => drupal_render($form['status'][$key]), 'align' => 'center'); 1557 1558 if (module_exists('throttle')) { 1559 $row[] = array('data' => drupal_render($form['throttle'][$key]), 'align' => 'center'); 1560 } 1561 $row[] = '<strong>'. drupal_render($form['name'][$key]) .'</strong>'; 1562 $row[] = drupal_render($form['version'][$key]); 1563 $row[] = array('data' => drupal_render($form['description'][$key]), 'class' => 'description'); 1564 $rows[] = $row; 1565 } 1566 $fieldset = array( 1567 '#title' => t($package), 1568 '#collapsible' => TRUE, 1569 '#collapsed' => ($package == 'Core - required'), 1570 '#value' => theme('table', $header, $rows, array('class' => 'package')), 1571 ); 1572 $output .= theme('fieldset', $fieldset); 1573 } 1574 1575 $output .= drupal_render($form); 1576 return $output; 1577 } 1578 1579 /** 1580 * Uninstall functions 1581 */ 1582 1583 /** 1584 * Builds a form of currently disabled modules. 1585 * 1586 * @param 1587 * $form_values Submitted form values. 1588 * @return 1589 * A form array representing the currently disabled modules. 1590 */ 1591 function system_modules_uninstall($form_values = NULL) { 1592 // Make sure the install API is available. 1593 include_once './includes/install.inc'; 1594 1595 // Display the confirm form if any modules have been submitted. 1596 if ($confirm_form = system_modules_uninstall_confirm_form($form_values)) { 1597 return $confirm_form; 1598 } 1599 1600 $form = array(); 1601 1602 // Pull all disabled modules from the system table. 1603 $disabled_modules = db_query("SELECT name, filename FROM {system} WHERE type = 'module' AND status = 0 AND schema_version > %d ORDER BY name", SCHEMA_UNINSTALLED); 1604 while ($module = db_fetch_object($disabled_modules)) { 1605 1606 // Grab the .info file and set name and description. 1607 $info = _module_parse_info_file(dirname($module->filename) .'/'. $module->name .'.info'); 1608 1609 // Load the .install file, and check for an uninstall hook. 1610 // If the hook exists, the module can be uninstalled. 1611 module_load_install($module->name); 1612 if (module_hook($module->name, 'uninstall')) { 1613 $form['modules'][$module->name]['name'] = array('#value' => $info['name'] ? $info['name'] : $module->name); 1614 $form['modules'][$module->name]['description'] = array('#value' => t($info['description'])); 1615 $options[$module->name] = ''; 1616 } 1617 } 1618 1619 // Only build the rest of the form if there are any modules available to uninstall. 1620 if (count($options)) { 1621 $form['uninstall'] = array( 1622 '#type' => 'checkboxes', 1623 '#options' => $options, 1624 ); 1625 $form['buttons']['submit'] = array( 1626 '#type' => 'button', 1627 '#value' => t('Uninstall'), 1628 ); 1629 $form['#multistep'] = TRUE; 1630 $form['#action'] = url('admin/build/modules/uninstall/confirm'); 1631 } 1632 1633 return $form; 1634 } 1635 1636 /** 1637 * Confirm uninstall of selected modules. 1638 * 1639 * @param 1640 * $form_values Submitted form values. 1641 * @return 1642 * A form array representing modules to confirm. 1643 */ 1644 function system_modules_uninstall_confirm_form($form_values) { 1645 // Nothing to build. 1646 if (!isset($form_values)) { 1647 return; 1648 } 1649 1650 // Construct the hidden form elements and list items. 1651 foreach (array_filter($form_values['uninstall']) as $module => $value) { 1652 $info = _module_parse_info_file(dirname(drupal_get_filename('module', $module)) .'/'. $module .'.info'); 1653 $uninstall[] = $info['name']; 1654 $form['uninstall'][$module] = array('#type' => 'hidden', 1655 '#value' => 1, 1656 ); 1657 } 1658 1659 // Display a confirm form if modules have been selected. 1660 if (isset($uninstall)) { 1661 $form['uninstall']['#tree'] = TRUE; 1662 $form['#multistep'] = TRUE; 1663 $form['modules'] = array('#value' => '<p>'. t('The following modules will be completely uninstalled from your site, and <em>all data from these modules will be lost</em>!') .'</p>'. theme('item_list', $uninstall)); 1664 $form = confirm_form( 1665 $form, 1666 t('Confirm uninstall'), 1667 'admin/build/modules/uninstall', 1668 t('Would you like to continue with uninstalling the above?'), 1669 t('Uninstall'), 1670 t('Cancel')); 1671 return $form; 1672 } 1673 } 1674 1675 /** 1676 * Themes a table of currently disabled modules. 1677 * 1678 * @param 1679 * $form The form array representing the currently disabled modules. 1680 * @return 1681 * An HTML string representing the table. 1682 */ 1683 function theme_system_modules_uninstall($form) { 1684 // No theming for the confirm form. 1685 if (isset($form['confirm'])) { 1686 return drupal_render($form); 1687 } 1688 1689 // Table headers. 1690 $header = array(t('Uninstall'), 1691 t('Name'), 1692 t('Description'), 1693 ); 1694 1695 // Display table. 1696 $rows = array(); 1697 foreach (element_children($form['modules']) as $module) { 1698 $rows[] = array( 1699 array('data' => drupal_render($form['uninstall'][$module]), 'align' => 'center'), 1700 '<strong>'. drupal_render($form['modules'][$module]['name']) .'</strong>', 1701 array('data' => drupal_render($form['modules'][$module]['description']), 'class' => 'description'), 1702 ); 1703 } 1704 1705 // Only display table if there are modules that can be uninstalled. 1706 if (!count($rows)) { 1707 $rows[] = array(array('data' => t('No modules are available to uninstall.'), 'colspan' => '3', 'align' => 'center', 'class' => 'message')); 1708 } 1709 1710 $output = theme('table', $header, $rows); 1711 $output .= drupal_render($form); 1712 1713 return $output; 1714 } 1715 1716 /** 1717 * Validates the submitted uninstall form. 1718 * 1719 * @param 1720 * $form_id The form ID. 1721 * @param 1722 * $form_values Submitted form values. 1723 */ 1724 function system_modules_uninstall_validate($form_id, $form_values) { 1725 // Form submitted, but no modules selected. 1726 if (!count(array_filter($form_values['uninstall']))) { 1727 drupal_set_message(t('No modules selected.'), 'error'); 1728 drupal_goto('admin/build/modules/uninstall'); 1729 } 1730 } 1731 1732 /** 1733 * Processes the submitted uninstall form. 1734 * 1735 * @param 1736 * $form_id The form ID. 1737 * @param 1738 * $form_values Submitted form values. 1739 */ 1740 function system_modules_uninstall_submit($form_id, $form_values) { 1741 // Make sure the install API is available. 1742 include_once './includes/install.inc'; 1743 1744 // Call the uninstall routine for each selected module. 1745 foreach (array_filter($form_values['uninstall']) as $module => $value) { 1746 drupal_uninstall_module($module); 1747 } 1748 drupal_set_message(t('The selected modules have been uninstalled.')); 1749 drupal_goto('admin/build/modules/uninstall'); 1750 } 1751 1752 /** 1753 * Menu callback: run cron manually. 1754 */ 1755 function system_run_cron() { 1756 // Run cron manually 1757 if (drupal_cron_run()) { 1758 drupal_set_message(t('Cron ran successfully')); 1759 } 1760 else { 1761 drupal_set_message(t('Cron run failed')); 1762 } 1763 1764 drupal_goto('admin/logs/status'); 1765 } 1766 1767 /** 1768 * Menu callback: return information about PHP. 1769 */ 1770 function system_php() { 1771 phpinfo(INFO_GENERAL | INFO_CONFIGURATION); 1772 exit(); 1773 } 1774 1775 function _system_sql($data, $keys) { 1776 $rows = array(); 1777 foreach ($keys as $key => $explanation) { 1778 if (isset($data[$key])) { 1779 $rows[] = array(check_plain($key), check_plain($data[$key]), $explanation); 1780 } 1781 } 1782 1783 return theme('table', array(t('Variable'), t('Value'), t('Description')), $rows); 1784 } 1785 1786 /** 1787 * Menu callback: return information about PHP. 1788 */ 1789 function system_sql() { 1790 1791 $result = db_query("SHOW STATUS"); 1792 while ($entry = db_fetch_object($result)) { 1793 $data[$entry->Variable_name] = $entry->Value; 1794 } 1795 1796 $output = '<h2>'. t('Command counters') .'</h2>'; 1797 $output .= _system_sql($data, array( 1798 'Com_select' => t('The number of <code>SELECT</code>-statements.'), 1799 'Com_insert' => t('The number of <code>INSERT</code>-statements.'), 1800 'Com_update' => t('The number of <code>UPDATE</code>-statements.'), 1801 'Com_delete' => t('The number of <code>DELETE</code>-statements.'), 1802 'Com_lock_tables' => t('The number of table locks.'), 1803 'Com_unlock_tables' => t('The number of table unlocks.') 1804 )); 1805 1806 $output .= '<h2>'. t('Query performance') .'</h2>'; 1807 $output .= _system_sql($data, array( 1808 'Select_full_join' => t('The number of joins without an index; should be zero.'), 1809 'Select_range_check' => t('The number of joins without an index; should be zero.'), 1810 'Sort_scan' => t('The number of sorts done without using an index; should be zero.'), 1811 'Table_locks_immediate' => t('The number of times a lock could be acquired immediately.'), 1812 'Table_locks_waited' => t('The number of times the server had to wait for a lock.') 1813 )); 1814 1815 $output .= '<h2>'. t('Query cache information') .'</h2>'; 1816 $output .= '<p>'. t('The MySQL query cache can improve performance of your site by storing the result of queries. Then, if an identical query is received later, the MySQL server retrieves the result from the query cache rather than parsing and executing the statement again.') .'</p>'; 1817 $output .= _system_sql($data, array( 1818 'Qcache_queries_in_cache' => t('The number of queries in the query cache.'), 1819 'Qcache_hits' => t('The number of times that MySQL found previous results in the cache.'), 1820 'Qcache_inserts' => t('The number of times that MySQL added a query to the cache (misses).'), 1821 'Qcache_lowmem_prunes' => t('The number of times that MySQL had to remove queries from the cache because it ran out of memory. Ideally should be zero.') 1822 )); 1823 1824 return $output; 1825 } 1826 1827 /** 1828 * Menu callback: displays the site status report. Can also be used as a pure check. 1829 * 1830 * @param $check 1831 * If true, only returns a boolean whether there are system status errors. 1832 */ 1833 function system_status($check = FALSE) { 1834 // Load .install files 1835 include_once './includes/install.inc'; 1836 drupal_load_updates(); 1837 1838 // Check run-time requirements and status information 1839 $requirements = module_invoke_all('requirements', 'runtime'); 1840 usort($requirements, '_system_sort_requirements'); 1841 1842 if ($check) { 1843 return drupal_requirements_severity($requirements) == REQUIREMENT_ERROR; 1844 } 1845 1846 return theme('status_report', $requirements); 1847 } 1848 1849 /** 1850 * Helper function to sort requirements. 1851 */ 1852 function _system_sort_requirements($a, $b) { 1853 return (isset($a['weight']) || isset($b['weight'])) ? $a['weight'] - $b['weight'] : strcmp($a['title'], $b['title']); 1854 } 1855 1856 /** 1857 * Theme status report 1858 */ 1859 function theme_status_report(&$requirements) { 1860 $i = 0; 1861 $output = '<table class="system-status-report">'; 1862 foreach ($requirements as $requirement) { 1863 if ($requirement['#type'] == '') { 1864 $class = ++$i % 2 == 0 ? 'even' : 'odd'; 1865 1866 $classes = array( 1867 REQUIREMENT_INFO => 'info', 1868 REQUIREMENT_OK => 'ok', 1869 REQUIREMENT_WARNING => 'warning', 1870 REQUIREMENT_ERROR => 'error', 1871 ); 1872 $class = $classes[(int)$requirement['severity']] .' '. $class; 1873 1874 // Output table row(s) 1875 if ($requirement['description']) { 1876 $output .= '<tr class="'. $class .' merge-down"><th>'. $requirement['title'] .'</th><td>'. $requirement['value'] .'</td></tr>'; 1877 $output .= '<tr class="'. $class .' merge-up"><td colspan="2">'. $requirement['description'] .'</td></tr>'; 1878 } 1879 else { 1880 $output .= '<tr class="'. $class .'"><th>'. $requirement['title'] .'</th><td>'. $requirement['value'] .'</td></tr>'; 1881 } 1882 } 1883 } 1884 1885 $output .= '</table>'; 1886 return $output; 1887 } 1888 1889 /** 1890 * Menu callback; displays a module's settings page. 1891 */ 1892 function system_settings_overview() { 1893 1894 // Check database setup if necessary 1895 if (function_exists('db_check_setup') && empty($_POST)) { 1896 db_check_setup(); 1897 } 1898 1899 $menu = menu_get_item(NULL, 'admin/settings'); 1900 $content = system_admin_menu_block($menu); 1901 1902 $output = theme('admin_block_content', $content); 1903 1904 return $output; 1905 } 1906 1907 /** 1908 * Menu callback; display theme configuration for entire site and individual themes. 1909 */ 1910 function system_theme_settings($key = '') { 1911 $directory_path = file_directory_path(); 1912 file_check_directory($directory_path, FILE_CREATE_DIRECTORY, 'file_directory_path'); 1913 1914 // Default settings are defined in theme_get_settings() in includes/theme.inc 1915 if ($key) { 1916 $settings = theme_get_settings($key); 1917 $var = str_replace('/', '_', 'theme_'. $key .'_settings'); 1918 $themes = system_theme_data(); 1919 $features = function_exists($themes[$key]->prefix . '_features') ? call_user_func($themes[$key]->prefix . '_features') : array(); 1920 } 1921 else { 1922 $settings = theme_get_settings(''); 1923 $var = 'theme_settings'; 1924 } 1925 1926 $form['var'] = array('#type' => 'hidden', '#value' => $var); 1927 1928 // Check for a new uploaded logo, and use that instead. 1929 if ($file = file_check_upload('logo_upload')) { 1930 if ($info = image_get_info($file->filepath)) { 1931 $parts = pathinfo($file->filename); 1932 $filename = ($key) ? str_replace('/', '_', $key) . '_logo.' . $parts['extension'] : 'logo.' . $parts['extension']; 1933 1934 if ($file = file_save_upload('logo_upload', $filename, 1)) { 1935 $_POST['default_logo'] = 0; 1936 $_POST['logo_path'] = $file->filepath; 1937 $_POST['toggle_logo'] = 1; 1938 } 1939 } 1940 else { 1941 form_set_error('file_upload', t('Only JPEG, PNG and GIF images are allowed to be used as logos.')); 1942 } 1943 } 1944 1945 // Check for a new uploaded favicon, and use that instead. 1946 if ($file = file_check_upload('favicon_upload')) { 1947 $parts = pathinfo($file->filename); 1948 $filename = ($key) ? str_replace('/', '_', $key) . '_favicon.' . $parts['extension'] : 'favicon.' . $parts['extension']; 1949 1950 if ($file = file_save_upload('favicon_upload', $filename, 1)) { 1951 $_POST['default_favicon'] = 0; 1952 $_POST['favicon_path'] = $file->filepath; 1953 $_POST['toggle_favicon'] = 1; 1954 } 1955 } 1956 1957 // Toggle settings 1958 $toggles = array( 1959 'toggle_logo' => t('Logo'), 1960 'toggle_name' => t('Site name'), 1961 'toggle_slogan' => t('Site slogan'), 1962 'toggle_mission' => t('Mission statement'), 1963 'toggle_node_user_picture' => t('User pictures in posts'), 1964 'toggle_comment_user_picture' => t('User pictures in comments'), 1965 'toggle_search' => t('Search box'), 1966 'toggle_favicon' => t('Shortcut icon') 1967 ); 1968 1969 // Some features are not always available 1970 $disabled = array(); 1971 if (!variable_get('user_pictures', 0)) { 1972 $disabled['toggle_node_user_picture'] = TRUE; 1973 $disabled['toggle_comment_user_picture'] = TRUE; 1974 } 1975 if (!module_exists('search')) { 1976 $disabled['toggle_search'] = TRUE; 1977 } 1978 1979 $form['theme_settings'] = array( 1980 '#type' => 'fieldset', 1981 '#title' => t('Toggle display'), 1982 '#description' => t('Enable or disable the display of certain page elements.'), 1983 ); 1984 foreach ($toggles as $name => $title) { 1985 if ((!$key) || in_array($name, $features)) { 1986 // disable search box if search.module is disabled 1987 $form['theme_settings'][$name] = array('#type' => 'checkbox', '#title' => $title, '#default_value' => $settings[$name]); 1988 if (isset($disabled[$name])) { 1989 $form['theme_settings'][$name]['#disabled'] = TRUE; 1990 } 1991 } 1992 } 1993 1994 // System wide only settings. 1995 if (!$key) { 1996 // Create neat 2-column layout for the toggles 1997 $form['theme_settings'] += array( 1998 '#prefix' => '<div class="theme-settings-left">', 1999 '#suffix' => '</div>', 2000 ); 2001 2002 // Toggle node display. 2003 $node_types = node_get_types('names'); 2004 if ($node_types) { 2005 $form['node_info'] = array( 2006 '#type' => 'fieldset', 2007 '#title' => t('Display post information on'), 2008 '#description' => t('Enable or disable the <em>submitted by Username on date</em> text when displaying posts of the following type.'), 2009 '#prefix' => '<div class="theme-settings-right">', 2010 '#suffix' => '</div>', 2011 ); 2012 foreach ($node_types as $type => $name) { 2013 $form['node_info']["toggle_node_info_$type"] = array('#type' => 'checkbox', '#title' => $name, '#default_value' => $settings["toggle_node_info_$type"]); 2014 } 2015 } 2016 } 2017 2018 // Logo settings 2019 if ((!$key) || in_array('toggle_logo', $features)) { 2020 $form['logo'] = array( 2021 '#type' => 'fieldset', 2022 '#title' => t('Logo image settings'), 2023 '#description' => t('If toggled on, the following logo will be displayed.'), 2024 '#attributes' => array('class' => 'theme-settings-bottom'), 2025 ); 2026 $form['logo']["default_logo"] = array( 2027 '#type' => 'checkbox', 2028 '#title' => t('Use the default logo'), 2029 '#default_value' => $settings['default_logo'], 2030 '#tree' => FALSE, 2031 '#description' => t('Check here if you want the theme to use the logo supplied with it.') 2032 ); 2033 $form['logo']['logo_path'] = array( 2034 '#type' => 'textfield', 2035 '#title' => t('Path to custom logo'), 2036 '#default_value' => $settings['logo_path'], 2037 '#description' => t('The path to the file you would like to use as your logo file instead of the default logo.')); 2038 2039 $form['logo']['logo_upload'] = array( 2040 '#type' => 'file', 2041 '#title' => t('Upload logo image'), 2042 '#maxlength' => 40, 2043 '#description' => t("If you don't have direct file access to the server, use this field to upload your logo.") 2044 ); 2045 } 2046 2047 // Icon settings 2048 if ((!$key) || in_array('toggle_favicon', $features)) { 2049 $form['favicon'] = array('#type' => 'fieldset', '#title' => t('Shortcut icon settings')); 2050 $form['favicon']['text'] = array('#value' => t('Your shortcut icon or \'favicon\' is displayed in the address bar and bookmarks of most browsers.')); 2051 $form['favicon']['default_favicon'] = array( 2052 '#type' => 'checkbox', 2053 '#title' => t('Use the default shortcut icon.'), 2054 '#default_value' => $settings['default_favicon'], 2055 '#description' => t('Check here if you want the theme to use the default shortcut icon.') 2056 ); 2057 $form['favicon']['favicon_path'] = array( 2058 '#type' => 'textfield', 2059 '#title' => t('Path to custom icon'), 2060 '#default_value' => $settings['favicon_path'], 2061 '#description' => t('The path to the image file you would like to use as your custom shortcut icon.') 2062 ); 2063 2064 $form['favicon']['favicon_upload'] = array( 2065 '#type' => 'file', 2066 '#title' => t('Upload icon image'), 2067 '#description' => t("If you don't have direct file access to the server, use this field to upload your shortcut icon.") 2068 ); 2069 } 2070 2071 if ($key) { 2072 // Template-specific settings 2073 $function = $themes[$key]->prefix .'_settings'; 2074 if (function_exists($function)) { 2075 if ($themes[$key]->template) { 2076 // file is a template or a style of a template 2077 $form['specific'] = array('#type' => 'fieldset', '#title' => t('Engine-specific settings'), '#description' => t('These settings only exist for all the templates and styles based on the %engine theme engine.', array('%engine' => $themes[$key]->prefix))); 2078 } 2079 else { 2080 // file is a theme or a style of a theme 2081 $form['specific'] = array('#type' => 'fieldset', '#title' => t('Theme-specific settings'), '#description' => t('These settings only exist for the %theme theme and all the styles based on it.', array('%theme' => $themes[$key]->prefix))); 2082 } 2083 $group = $function(); 2084 $form['specific'] = array_merge($form['specific'], (is_array($group) ? $group : array())); 2085 } 2086 } 2087 $form['#attributes'] = array('enctype' => 'multipart/form-data'); 2088 2089 return system_settings_form($form); 2090 } 2091 2092 /** 2093 * Implementation of hook_node_type(). 2094 * 2095 * Updates theme settings after a node type change. 2096 */ 2097 function system_node_type($op, $info) { 2098 if ($op == 'update' && !empty($info->old_type) && $info->type != $info->old_type) { 2099 $old = 'toggle_node_info_'. $info->old_type; 2100 $new = 'toggle_node_info_'. $info->type; 2101 2102 $theme_settings = variable_get('theme_settings', array()); 2103 if (isset($theme_settings[$old])) { 2104 $theme_settings[$new] = $theme_settings[$old]; 2105 unset($theme_settings[$old]); 2106 variable_set('theme_settings', $theme_settings); 2107 } 2108 } 2109 } 2110 2111 /** 2112 * Output a confirmation form 2113 * 2114 * This function returns a complete form for confirming an action. A link is 2115 * offered to go back to the item that is being changed in case the user changes 2116 * his/her mind. 2117 * 2118 * You can check for the existence of $_POST[$name] (where $name 2119 * is usually 'confirm') to check if the confirmation was successful or 2120 * use the regular submit model. 2121 * 2122 * @param $form 2123 * Additional elements to inject into the form, for example hidden elements. 2124 * @param $question 2125 * The question to ask the user (e.g. "Are you sure you want to delete the 2126 * block <em>foo</em>?"). 2127 * @param $path 2128 * The page to go to if the user denies the action. 2129 * Can be either a drupal path, or an array with the keys 'path', 'query', 'fragment'. 2130 * @param $description 2131 * Additional text to display (defaults to "This action cannot be undone."). 2132 * @param $yes 2133 * A caption for the button which confirms the action (e.g. "Delete", 2134 * "Replace", ...). 2135 * @param $no 2136 * A caption for the link which denies the action (e.g. "Cancel"). 2137 * @param $name 2138 * The internal name used to refer to the confirmation item. 2139 * @return 2140 * The form. 2141 */ 2142 function confirm_form($form, $question, $path, $description = NULL, $yes = NULL, $no = NULL, $name = 'confirm') { 2143 $description = isset($description) ? $description : t('This action cannot be undone.'); 2144 2145 // Prepare cancel link 2146 $query = $fragment = NULL; 2147 if (is_array($path)) { 2148 $query = isset($path['query']) ? $path['query'] : NULL; 2149 $fragment = isset($path['fragment']) ? $path['fragment'] : NULL; 2150 $path = isset($path['path']) ? $path['path'] : NULL; 2151 } 2152 $cancel = l($no ? $no : t('Cancel'), $path, array(), $query, $fragment); 2153 2154 drupal_set_title($question); 2155 $form['#attributes'] = array('class' => 'confirmation'); 2156 $form['description'] = array('#value' => $description); 2157 $form[$name] = array('#type' => 'hidden', '#value' => 1); 2158 2159 $form['actions'] = array('#prefix' => '<div class="container-inline">', '#suffix' => '</div>'); 2160 $form['actions']['submit'] = array('#type' => 'submit', '#value' => $yes ? $yes : t('Confirm')); 2161 $form['actions']['cancel'] = array('#value' => $cancel); 2162 $form['#base'] = 'confirm_form'; 2163 return $form; 2164 } 2165 2166 /** 2167 * Determine if a user is in compact mode. 2168 */ 2169 function system_admin_compact_mode() { 2170 global $user; 2171 return (isset($user->admin_compact_mode)) ? $user->admin_compact_mode : variable_get('admin_compact_mode', FALSE); 2172 } 2173 2174 /** 2175 * This function formats an administrative page for viewing. 2176 * 2177 * @param $blocks 2178 * An array of blocks to display. Each array should include a 2179 * 'title', a 'description', a formatted 'content' and a 2180 * 'position' which will control which container it will be 2181 * in. This is usually 'left' or 'right'. 2182 * @themeable 2183 */ 2184 function theme_admin_page($blocks) { 2185 $stripe = 0; 2186 $container = array(); 2187 2188 foreach ($blocks as $block) { 2189 if ($block_output = theme('admin_block', $block)) { 2190 if (!$block['position']) { 2191 // perform automatic striping. 2192 $block['position'] = $stripe++ % 2 ? 'left' : 'right'; 2193 } 2194 $container[$block['position']] .= $block_output; 2195 } 2196 } 2197 2198 $output = '<div class="admin clear-block">'; 2199 $output .= '<div class="compact-link">'; 2200 if (system_admin_compact_mode()) { 2201 $output .= l(t('Show descriptions'), 'admin/compact/off', array('title' => t('Produce a less compact layout that includes descriptions.'))); 2202 } 2203 else { 2204 $output .= l(t('Hide descriptions'), 'admin/compact/on', array('title' => t("Produce a more compact layout that doesn't include descriptions."))); 2205 } 2206 $output .= '</div>'; 2207 2208 foreach ($container as $id => $data) { 2209 $output .= '<div class="'. $id .' clear-block">'; 2210 $output .= $data; 2211 $output .= '</div>'; 2212 } 2213 $output .= '</div>'; 2214 return $output; 2215 } 2216 2217 /** 2218 * This function formats an administrative block for display. 2219 * 2220 * @param $block 2221 * An array containing information about the block. It should 2222 * include a 'title', a 'description' and a formatted 'content'. 2223 * @themeable 2224 */ 2225 function theme_admin_block($block) { 2226 // Don't display the block if it has no content to display. 2227 if (!$block['content']) { 2228 return ''; 2229 } 2230 2231 $output = <<< EOT 2232 <div class="admin-panel"> 2233 <h3> 2234 $block[title] 2235 </h3> 2236 <div class="body"> 2237 <p class="description"> 2238 $block[description] 2239 </p> 2240 $block[content] 2241 </div> 2242 </div> 2243 EOT; 2244 return $output; 2245 } 2246 2247 /** 2248 * This function formats the content of an administrative block. 2249 * 2250 * @param $block 2251 * An array containing information about the block. It should 2252 * include a 'title', a 'description' and a formatted 'content'. 2253 * @themeable 2254 */ 2255 function theme_admin_block_content($content) { 2256 if (!$content) { 2257 return ''; 2258 } 2259 2260 if (system_admin_compact_mode()) { 2261 $output = '<ul class="menu">'; 2262 foreach ($content as $item) { 2263 $output .= '<li class="leaf">'. l($item['title'], $item['path'], array('title' => $item['description'])) .'</li>'; 2264 } 2265 $output .= '</ul>'; 2266 } 2267 else { 2268 $output = '<dl class="admin-list">'; 2269 foreach ($content as $item) { 2270 $output .= '<dt>'. l($item['title'], $item['path']) .'</dt>'; 2271 $output .= '<dd>'. $item['description'] .'</dd>'; 2272 } 2273 $output .= '</dl>'; 2274 } 2275 return $output; 2276 } 2277 2278 /** 2279 * Menu callback; prints a listing of admin tasks for each installed module. 2280 */ 2281 function system_admin_by_module() { 2282 $modules = module_rebuild_cache(); 2283 $menu_items = array(); 2284 foreach ($modules as $file) { 2285 $module = $file->name; 2286 if ($module == 'help') { 2287 continue; 2288 } 2289 2290 $admin_tasks = system_get_module_admin_tasks($module); 2291 2292 // Only display a section if there are any available tasks. 2293 if (count($admin_tasks)) { 2294 2295 // Check for help links. 2296 if (module_invoke($module, 'help', "admin/help#$module")) { 2297 $admin_tasks[100] = l(t('Get help'), "admin/help/$module"); 2298 } 2299 2300 // Sort. 2301 ksort($admin_tasks); 2302 2303 $menu_items[$file->info['name']] = array($file->info['description'], $admin_tasks); 2304 } 2305 } 2306 return theme('system_admin_by_module', $menu_items); 2307 } 2308 2309 function system_get_module_admin_tasks($module) { 2310 $admin_access = user_access('administer access control'); 2311 $menu = menu_get_menu(); 2312 $admin_tasks = array(); 2313 2314 // Check for permissions. 2315 if (module_hook($module, 'perm') && $admin_access) { 2316 $admin_tasks[-1] = l(t('Configure permissions'), 'admin/user/access', NULL, NULL, 'module-'. $module); 2317 } 2318 2319 // Check for menu items that are admin links. 2320 if ($items = module_invoke($module, 'menu', TRUE)) { 2321 foreach ($items as $item) { 2322 $parts = explode('/', $item['path']); 2323 $n = count($parts); 2324 if ((!isset($item['type']) || ($item['type'] & MENU_VISIBLE_IN_TREE)) && ($parts[0] == 'admin') && ($n >= 3) && _menu_item_is_accessible($menu['path index'][$item['path']])) { 2325 $admin_tasks[$item['title']] = l($item['title'], $item['path']); 2326 } 2327 } 2328 } 2329 2330 return $admin_tasks; 2331 } 2332 2333 /** 2334 * Theme output of the dashboard page. 2335 */ 2336 function theme_system_admin_by_module($menu_items) { 2337 $stripe = 0; 2338 $output = ''; 2339 $container = array(); 2340 2341 // Iterate over all modules 2342 foreach ($menu_items as $module => $block) { 2343 list($description, $items) = $block; 2344 2345 // Output links 2346 if (count($items)) { 2347 $block = array(); 2348 $block['title'] = $module; 2349 $block['content'] = theme('item_list', $items); 2350 $block['description'] = t($description); 2351 2352 if ($block_output = theme('admin_block', $block)) { 2353 if (!$block['position']) { 2354 // Perform automatic striping. 2355 $block['position'] = ++$stripe % 2 ? 'left' : 'right'; 2356 } 2357 $container[$block['position']] .= $block_output; 2358 } 2359 } 2360 } 2361 2362 $output = '<div class="admin">'; 2363 foreach ($container as $id => $data) { 2364 $output .= '<div class="'. $id .' clear-block">'; 2365 $output .= $data; 2366 $output .= '</div>'; 2367 } 2368 $output .= '</div>'; 2369 2370 return $output; 2371 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| [ Powered by PHPXref - Served by Debian GNU/Linux ] |