[ Index ] |
|
Code source de Drupal 5.3 |
1 <?php 2 // $Id: system.module,v 1.440.2.19 2007/10/17 21:29:00 drumm Exp $ 3 4 /** 5 * @file 6 * Configuration system that lets administrators modify the workings of the site. 7 */ 8 9 define('VERSION', '5.3'); 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 system 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(4): 33 $reference = explode('.', arg(4), 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 to be used as the "From" address by the auto-mailer during registration, new password requests, notifications, etc. To lessen the likelihood of e-mail being marked as spam, this e-mail address should use the same domain as the website.'), 551 '#required' => TRUE, 552 ); 553 $form['site_slogan'] = array( 554 '#type' => 'textfield', 555 '#title' => t('Slogan'), 556 '#default_value' => variable_get('site_slogan', ''), 557 '#description' => t('The slogan of this website. Some themes display a slogan when available.') 558 ); 559 560 $form['site_mission'] = array( 561 '#type' => 'textarea', 562 '#title' => t('Mission'), 563 '#default_value' => variable_get('site_mission', ''), 564 '#description' => t('Your site\'s mission statement or focus.') 565 ); 566 $form['site_footer'] = array( 567 '#type' => 'textarea', 568 '#title' => t('Footer message'), 569 '#default_value' => variable_get('site_footer', ''), 570 '#description' => t('This text will be displayed at the bottom of each page. Useful for adding a copyright notice to your pages.') 571 ); 572 $form['anonymous'] = array( 573 '#type' => 'textfield', 574 '#title' => t('Anonymous user'), 575 '#default_value' => variable_get('anonymous', t('Anonymous')), 576 '#description' => t('The name used to indicate anonymous users.') 577 ); 578 $form['site_frontpage'] = array( 579 '#type' => 'textfield', 580 '#title' => t('Default front page'), 581 '#default_value' => variable_get('site_frontpage', 'node'), 582 '#size' => 40, 583 '#description' => t('The home page displays content from this relative URL. If unsure, specify "node".'), 584 '#field_prefix' => url(NULL, NULL, NULL, TRUE) . (variable_get('clean_url', 0) ? '' : '?q=') 585 ); 586 587 return system_settings_form($form); 588 } 589 590 function system_clean_url_settings() { 591 // We check for clean URL support using an image on the client side. 592 $form['clean_url'] = array( 593 '#type' => 'radios', 594 '#title' => t('Clean URLs'), 595 '#default_value' => variable_get('clean_url', 0), 596 '#options' => array(t('Disabled'), t('Enabled')), 597 '#description' => t('This option makes Drupal emit "clean" URLs (i.e. without <code>?q=</code> in the URL.)'), 598 ); 599 600 if (!variable_get('clean_url', 0)) { 601 if (strpos(request_uri(), '?q=') !== FALSE) { 602 $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>')); 603 $form['clean_url']['#disabled'] = TRUE; 604 } 605 else { 606 $form['clean_url']['#description'] .= t(' You have successfully demonstrated that clean URLs work on your server. You may enable/disable them as you wish.'); 607 $form['#collapsed'] = FALSE; 608 } 609 } 610 611 return system_settings_form($form); 612 } 613 614 function system_error_reporting_settings() { 615 616 $form['site_403'] = array( 617 '#type' => 'textfield', 618 '#title' => t('Default 403 (access denied) page'), 619 '#default_value' => variable_get('site_403', ''), 620 '#size' => 40, 621 '#description' => t('This page is displayed when the requested document is denied to the current user. If unsure, specify nothing.'), 622 '#field_prefix' => url(NULL, NULL, NULL, TRUE) . (variable_get('clean_url', 0) ? '' : '?q=') 623 ); 624 625 $form['site_404'] = array( 626 '#type' => 'textfield', 627 '#title' => t('Default 404 (not found) page'), 628 '#default_value' => variable_get('site_404', ''), 629 '#size' => 40, 630 '#description' => t('This page is displayed when no other content matches the requested document. If unsure, specify nothing.'), 631 '#field_prefix' => url(NULL, NULL, NULL, TRUE) . (variable_get('clean_url', 0) ? '' : '?q=') 632 ); 633 634 $form['error_level'] = array( 635 '#type' => 'select', '#title' => t('Error reporting'), '#default_value' => variable_get('error_level', 1), 636 '#options' => array(t('Write errors to the log'), t('Write errors to the log and to the screen')), 637 '#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.') 638 ); 639 640 $period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200), 'format_interval'); 641 $period['1000000000'] = t('Never'); 642 $form['watchdog_clear'] = array( 643 '#type' => 'select', 644 '#title' => t('Discard log entries older than'), 645 '#default_value' => variable_get('watchdog_clear', 604800), 646 '#options' => $period, 647 '#description' => t('The time log entries should be kept. Older entries will be automatically discarded. Requires crontab.') 648 ); 649 650 return system_settings_form($form); 651 } 652 653 function system_performance_settings() { 654 655 $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>'; 656 657 $problem_modules = array_unique(array_merge(module_implements('init'), module_implements('exit'))); 658 sort($problem_modules); 659 660 if (count($problem_modules) > 0) { 661 $description .= '<p>'. t('<strong class="error">The following enabled modules are incompatible with aggressive mode caching and might not function properly: %modules</strong>', array('%modules' => implode(', ', $problem_modules))) .'.</p>'; 662 } 663 else { 664 $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>'; 665 } 666 $form['page_cache'] = array( 667 '#type' => 'fieldset', 668 '#title' => t('Page cache'), 669 '#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.'), 670 ); 671 672 $form['page_cache']['cache'] = array( 673 '#type' => 'radios', 674 '#title' => t('Caching mode'), 675 '#default_value' => variable_get('cache', CACHE_DISABLED), 676 '#options' => array(CACHE_DISABLED => t('Disabled'), CACHE_NORMAL => t('Normal (recommended, no side effects)'), CACHE_AGGRESSIVE => t('Aggressive (experts only, possible side effects)')), 677 '#description' => $description 678 ); 679 680 $period = drupal_map_assoc(array(0, 60, 180, 300, 600, 900, 1800, 2700, 3600, 10800, 21600, 32400, 43200, 86400), 'format_interval'); 681 $period[0] = t('none'); 682 $form['page_cache']['cache_lifetime'] = array( 683 '#type' => 'select', 684 '#title' => t('Minimum cache lifetime'), 685 '#default_value' => variable_get('cache_lifetime', 0), 686 '#options' => $period, 687 '#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.') 688 ); 689 690 $form['bandwidth_optimizations'] = array( 691 '#type' => 'fieldset', 692 '#title' => t('Bandwidth optimizations'), 693 '#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.') 694 ); 695 696 $directory = file_directory_path(); 697 $is_writable = is_dir($directory) && is_writable($directory) && (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC); 698 $form['bandwidth_optimizations']['preprocess_css'] = array( 699 '#type' => 'radios', 700 '#title' => t('Aggregate and compress CSS files'), 701 '#default_value' => intval(variable_get('preprocess_css', FALSE) && $is_writable), 702 '#disabled' => !$is_writable, 703 '#options' => array(t('Disabled'), t('Enabled')), 704 '#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."), 705 ); 706 707 $form['#submit']['system_settings_form_submit'] = array(); 708 $form['#submit']['drupal_clear_css_cache'] = array(); 709 710 return system_settings_form($form); 711 } 712 713 function system_file_system_settings() { 714 715 $form['file_directory_path'] = array( 716 '#type' => 'textfield', 717 '#title' => t('File system path'), 718 '#default_value' => file_directory_path(), 719 '#maxlength' => 255, 720 '#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.'), 721 '#after_build' => array('system_check_directory'), 722 ); 723 724 $form['file_directory_temp'] = array( 725 '#type' => 'textfield', 726 '#title' => t('Temporary directory'), 727 '#default_value' => file_directory_temp(), 728 '#maxlength' => 255, 729 '#description' => t('Location where uploaded files will be kept during previews. Relative paths will be resolved relative to the Drupal installation directory.'), 730 '#after_build' => array('system_check_directory'), 731 ); 732 733 $form['file_downloads'] = array( 734 '#type' => 'radios', 735 '#title' => t('Download method'), 736 '#default_value' => variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC), 737 '#options' => array(FILE_DOWNLOADS_PUBLIC => t('Public - files are available using HTTP directly.'), FILE_DOWNLOADS_PRIVATE => t('Private - files are transferred by Drupal.')), 738 '#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.') 739 ); 740 741 return system_settings_form($form); 742 } 743 744 function system_image_toolkit_settings() { 745 $toolkits_available = image_get_available_toolkits(); 746 if (count($toolkits_available) > 1) { 747 $form['image_toolkit'] = array( 748 '#type' => 'radios', 749 '#title' => t('Select an image processing toolkit'), 750 '#default_value' => variable_get('image_toolkit', image_get_toolkit()), 751 '#options' => $toolkits_available 752 ); 753 } 754 else { 755 $form['image_toolkit'] = array('#value' => '<p>'. t("No image toolkits found. Drupal will use PHP's built-in GD library for image handling.") .'</p>'); 756 } 757 $form['image_toolkit_settings'] = image_toolkit_invoke('settings'); 758 return system_settings_form($form); 759 } 760 761 function system_rss_feeds_settings() { 762 763 $form['feed_default_items'] = array( 764 '#type' => 'select', 765 '#title' => t('Number of items per feed'), 766 '#default_value' => variable_get('feed_default_items', 10), 767 '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30)), 768 '#description' => t('The default number of items to include in a feed.') 769 ); 770 $form['feed_item_length'] = array( 771 '#type' => 'select', 772 '#title' => t('Display of XML feed items'), 773 '#default_value' => variable_get('feed_item_length', 'teaser'), 774 '#options' => array('title' => t('Titles only'), 'teaser' => t('Titles plus teaser'), 'fulltext' => t('Full text')), 775 '#description' => t('Global setting for the length of XML feed items that are output by default.') 776 ); 777 778 return system_settings_form($form); 779 } 780 781 function system_date_time_settings() { 782 // Date settings: 783 $zones = _system_zonelist(); 784 785 // Date settings: possible date formats 786 $dateshort = array('Y-m-d H:i', 'm/d/Y - H:i', 'd/m/Y - H:i', 'Y/m/d - H:i', 787 'd.m.Y - H:i', 'm/d/Y - g:ia', 'd/m/Y - g:ia', 'Y/m/d - g:ia', 788 'M j Y - H:i', 'j M Y - H:i', 'Y M j - H:i', 789 'M j Y - g:ia', 'j M Y - g:ia', 'Y M j - g:ia'); 790 $datemedium = array('D, Y-m-d H:i', 'D, m/d/Y - H:i', 'D, d/m/Y - H:i', 791 'D, Y/m/d - H:i', 'F j, Y - H:i', 'j F, Y - H:i', 'Y, F j - H:i', 792 'D, m/d/Y - g:ia', 'D, d/m/Y - g:ia', 'D, Y/m/d - g:ia', 793 'F j, Y - g:ia', 'j F Y - g:ia', 'Y, F j - g:ia', 'j. F Y - G:i'); 794 $datelong = array('l, F j, Y - H:i', 'l, j F, Y - H:i', 'l, Y, F j - H:i', 795 'l, F j, Y - g:ia', 'l, j F Y - g:ia', 'l, Y, F j - g:ia', 'l, j. F Y - G:i'); 796 797 // Date settings: construct choices for user 798 foreach ($dateshort as $f) { 799 $dateshortchoices[$f] = format_date(time(), 'custom', $f); 800 } 801 foreach ($datemedium as $f) { 802 $datemediumchoices[$f] = format_date(time(), 'custom', $f); 803 } 804 foreach ($datelong as $f) { 805 $datelongchoices[$f] = format_date(time(), 'custom', $f); 806 } 807 808 $form['date_default_timezone'] = array( 809 '#type' => 'select', 810 '#title' => t('Default time zone'), 811 '#default_value' => variable_get('date_default_timezone', 0), 812 '#options' => $zones, 813 '#description' => t('Select the default site time zone.') 814 ); 815 816 $form['configurable_timezones'] = array( 817 '#type' => 'radios', 818 '#title' => t('Configurable time zones'), 819 '#default_value' => variable_get('configurable_timezones', 1), 820 '#options' => array(t('Disabled'), t('Enabled')), 821 '#description' => t('Enable or disable user-configurable time zones. When enabled, users can set their own time zone and dates will be updated accordingly.') 822 ); 823 824 $form['date_format_short'] = array( 825 '#type' => 'select', 826 '#title' => t('Short date format'), 827 '#default_value' => variable_get('date_format_short', $dateshort[1]), 828 '#options' => $dateshortchoices, 829 '#description' => t('The short format of date display.') 830 ); 831 832 $form['date_format_medium'] = array( 833 '#type' => 'select', 834 '#title' => t('Medium date format'), 835 '#default_value' => variable_get('date_format_medium', $datemedium[1]), 836 '#options' => $datemediumchoices, 837 '#description' => t('The medium sized date display.') 838 ); 839 840 $form['date_format_long'] = array( 841 '#type' => 'select', 842 '#title' => t('Long date format'), 843 '#default_value' => variable_get('date_format_long', $datelong[0]), 844 '#options' => $datelongchoices, 845 '#description' => t('Longer date format used for detailed display.') 846 ); 847 848 $form['date_first_day'] = array( 849 '#type' => 'select', 850 '#title' => t('First day of week'), 851 '#default_value' => variable_get('date_first_day', 0), 852 '#options' => array(0 => t('Sunday'), 1 => t('Monday'), 2 => t('Tuesday'), 3 => t('Wednesday'), 4 => t('Thursday'), 5 => t('Friday'), 6 => t('Saturday')), 853 '#description' => t('The first day of the week for calendar views.') 854 ); 855 856 return system_settings_form($form); 857 } 858 859 function system_site_maintenance_settings() { 860 861 $form['site_offline'] = array( 862 '#type' => 'radios', 863 '#title' => t('Site status'), 864 '#default_value' => variable_get('site_offline', 0), 865 '#options' => array(t('Online'), t('Off-line')), 866 '#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'))), 867 ); 868 869 $form['site_offline_message'] = array( 870 '#type' => 'textarea', 871 '#title' => t('Site off-line message'), 872 '#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')))), 873 '#description' => t('Message to show visitors when the site is in off-line mode.') 874 ); 875 876 return system_settings_form($form); 877 } 878 879 /** 880 * Checks the existence of the directory specified in $form_element. This 881 * function is called from the system_settings form to check both the 882 * file_directory_path and file_directory_temp directories. If validation 883 * fails, the form element is flagged with an error from within the 884 * file_check_directory function. 885 * 886 * @param $form_element 887 * The form element containing the name of the directory to check. 888 */ 889 function system_check_directory($form_element) { 890 file_check_directory($form_element['#value'], FILE_CREATE_DIRECTORY, $form_element['#parents'][0]); 891 return $form_element; 892 } 893 894 /** 895 * Retrieves the current status of an array of files in the system table. 896 */ 897 function system_get_files_database(&$files, $type) { 898 // Extract current files from database. 899 $result = db_query("SELECT filename, name, type, status, throttle, schema_version FROM {system} WHERE type = '%s'", $type); 900 while ($file = db_fetch_object($result)) { 901 if (isset($files[$file->name]) && is_object($files[$file->name])) { 902 $file->old_filename = $file->filename; 903 foreach ($file as $key => $value) { 904 if (!isset($files[$file->name]) || !isset($files[$file->name]->$key)) { 905 $files[$file->name]->$key = $value; 906 } 907 } 908 } 909 } 910 } 911 912 /** 913 * Collect data about all currently available themes 914 */ 915 function system_theme_data() { 916 include_once './includes/install.inc'; 917 918 // Find themes 919 $themes = drupal_system_listing('\.theme$', 'themes'); 920 921 // Find theme engines 922 $engines = drupal_system_listing('\.engine$', 'themes/engines'); 923 924 // can't iterate over array itself as it uses a copy of the array items 925 foreach (array_keys($themes) as $key) { 926 drupal_get_filename('theme', $themes[$key]->name, $themes[$key]->filename); 927 drupal_load('theme', $themes[$key]->name); 928 $themes[$key]->owner = $themes[$key]->filename; 929 $themes[$key]->prefix = $key; 930 } 931 932 // Remove all theme engines from the system table 933 db_query("DELETE FROM {system} WHERE type = 'theme_engine'"); 934 935 foreach ($engines as $engine) { 936 // Insert theme engine into system table 937 drupal_get_filename('theme_engine', $engine->name, $engine->filename); 938 drupal_load('theme_engine', $engine->name); 939 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); 940 941 // Add templates to the site listing 942 foreach (call_user_func($engine->name .'_templates') as $template) { 943 // Do not double-insert templates with theme files in their directory, 944 // but do register their engine data. 945 if (array_key_exists($template->name, $themes)) { 946 $themes[$template->name]->template = TRUE; 947 $themes[$template->name]->owner = $engine->filename; 948 $themes[$template->name]->prefix = $engine->name; 949 } 950 else { 951 $template->template = TRUE; 952 $template->name = basename(dirname($template->filename)); 953 $template->owner = $engine->filename; 954 $template->prefix = $engine->name; 955 956 $themes[$template->name] = $template; 957 } 958 } 959 } 960 961 // Find styles in each theme's directory. 962 foreach ($themes as $theme) { 963 foreach (file_scan_directory(dirname($theme->filename), 'style.css$') as $style) { 964 $style->style = TRUE; 965 $style->template = isset($theme->template) ? $theme->template : FALSE; 966 $style->name = basename(dirname($style->filename)); 967 $style->owner = $theme->filename; 968 $style->prefix = $theme->template ? $theme->prefix : $theme->name; 969 // do not double-insert styles with theme files in their directory 970 if (array_key_exists($style->name, $themes)) { 971 continue; 972 } 973 $themes[$style->name] = $style; 974 } 975 } 976 977 // Extract current files from database. 978 system_get_files_database($themes, 'theme'); 979 980 db_query("DELETE FROM {system} WHERE type = 'theme'"); 981 982 foreach ($themes as $theme) { 983 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); 984 } 985 986 return $themes; 987 } 988 989 /** 990 * Get a list of available regions from a specified theme. 991 * 992 * @param $theme_key 993 * The name of a theme. 994 * @return 995 * An array of regions in the form $region['name'] = 'description'. 996 */ 997 function system_region_list($theme_key) { 998 static $list = array(); 999 1000 if (!array_key_exists($theme_key, $list)) { 1001 $theme = db_fetch_object(db_query("SELECT * FROM {system} WHERE type = 'theme' AND name = '%s'", $theme_key)); 1002 1003 // Stylesheets can't have regions; use its theme. 1004 if (strpos($theme->filename, '.css')) { 1005 return system_region_list(basename(dirname($theme->description))); 1006 } 1007 1008 // If this is a custom theme, load it in before moving on. 1009 if (file_exists($file = dirname($theme->filename) .'/'. $theme_key .'.theme')) { 1010 include_once "./$file"; 1011 } 1012 1013 $regions = array(); 1014 1015 // This theme has defined its own regions. 1016 if (function_exists($theme_key .'_regions')) { 1017 $regions = call_user_func($theme_key .'_regions'); 1018 } 1019 // File is an engine; include its regions. 1020 else if (strpos($theme->description, '.engine')) { 1021 include_once './'. $theme->description; 1022 $theme_engine = basename($theme->description, '.engine'); 1023 $regions = function_exists($theme_engine .'_regions') ? call_user_func($theme_engine .'_regions') : array(); 1024 } 1025 1026 $list[$theme_key] = $regions; 1027 } 1028 1029 return $list[$theme_key]; 1030 } 1031 1032 /** 1033 * Get the name of the default region for a given theme. 1034 * 1035 * @param $theme 1036 * The name of a theme. 1037 * @return 1038 * A string that is the region name. 1039 */ 1040 function system_default_region($theme) { 1041 $regions = array_keys(system_region_list($theme)); 1042 return $regions[0]; 1043 } 1044 1045 /** 1046 * Assign an initial, default set of blocks for a theme. 1047 * 1048 * This function is called the first time a new theme is enabled. The new theme 1049 * gets a copy of the default theme's blocks, with the difference that if a 1050 * particular region isn't available in the new theme, the block is assigned 1051 * to the new theme's default region. 1052 * 1053 * @param $theme 1054 * The name of a theme. 1055 */ 1056 function system_initialize_theme_blocks($theme) { 1057 // Initialize theme's blocks if none already registered. 1058 if (!(db_num_rows(db_query("SELECT module FROM {blocks} WHERE theme = '%s'", $theme)))) { 1059 $default_theme = variable_get('theme_default', 'garland'); 1060 $regions = system_region_list($theme); 1061 $result = db_query("SELECT * FROM {blocks} WHERE theme = '%s'", $default_theme); 1062 while ($block = db_fetch_array($result)) { 1063 // If the region isn't supported by the theme, assign the block to the theme's default region. 1064 if (!array_key_exists($block['region'], $regions)) { 1065 $block['region'] = system_default_region($theme); 1066 } 1067 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)", 1068 $block['module'], $block['delta'], $theme, $block['status'], $block['weight'], $block['region'], $block['visibility'], $block['pages'], $block['custom'], $block['throttle']); 1069 } 1070 } 1071 } 1072 1073 /** 1074 * Add default buttons to a form and set its prefix 1075 */ 1076 function system_settings_form($form) { 1077 $form['buttons']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration') ); 1078 $form['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset to defaults') ); 1079 1080 if (!empty($_POST) && form_get_errors()) { 1081 drupal_set_message(t('The settings have not been saved because of the errors.'), 'error'); 1082 } 1083 $form['#base'] = 'system_settings_form'; 1084 return $form; 1085 } 1086 1087 function system_theme_settings_submit($form_id, $form_values) { 1088 $op = isset($_POST['op']) ? $_POST['op'] : ''; 1089 $key = $form_values['var']; 1090 1091 // Exclude unnecessary elements. 1092 unset($form_values['var'], $form_values['submit'], $form_values['reset'], $form_values['form_id']); 1093 1094 if ($op == t('Reset to defaults')) { 1095 variable_del($key); 1096 drupal_set_message(t('The configuration options have been reset to their default values.')); 1097 } 1098 else { 1099 variable_set($key, $form_values); 1100 drupal_set_message(t('The configuration options have been saved.')); 1101 } 1102 1103 cache_clear_all(); 1104 } 1105 1106 /** 1107 * Execute the system_settings_form. 1108 * 1109 * If you want node type configure style handling of your checkboxes, 1110 * add an array_filter value to your form. 1111 * 1112 */ 1113 function system_settings_form_submit($form_id, $form_values) { 1114 $op = isset($form_values['op']) ? $form_values['op'] : ''; 1115 1116 // Exclude unnecessary elements. 1117 unset($form_values['submit'], $form_values['reset'], $form_values['form_id'], $form_values['op'], $form_values['form_token']); 1118 1119 foreach ($form_values as $key => $value) { 1120 if ($op == t('Reset to defaults')) { 1121 variable_del($key); 1122 } 1123 else { 1124 if (is_array($value) && isset($form_values['array_filter'])) { 1125 $value = array_keys(array_filter($value)); 1126 } 1127 variable_set($key, $value); 1128 } 1129 } 1130 if ($op == t('Reset to defaults')) { 1131 drupal_set_message(t('The configuration options have been reset to their default values.')); 1132 } 1133 else { 1134 drupal_set_message(t('The configuration options have been saved.')); 1135 } 1136 1137 menu_rebuild(); 1138 } 1139 1140 /** 1141 * Menu callback; displays a listing of all themes. 1142 */ 1143 function system_themes() { 1144 1145 drupal_clear_css_cache(); 1146 $themes = system_theme_data(); 1147 ksort($themes); 1148 1149 foreach ($themes as $info) { 1150 $info->screenshot = dirname($info->filename) .'/screenshot.png'; 1151 $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'); 1152 1153 $form[$info->name]['screenshot'] = array('#value' => $screenshot); 1154 $form[$info->name]['description'] = array('#type' => 'item', '#title' => $info->name, '#value' => dirname($info->filename)); 1155 $options[$info->name] = ''; 1156 if ($info->status) { 1157 $status[] = $info->name; 1158 } 1159 if ($info->status && (function_exists($info->prefix .'_settings') || function_exists($info->prefix .'_features'))) { 1160 $form[$info->name]['operations'] = array('#value' => l(t('configure'), 'admin/build/themes/settings/'. $info->name) ); 1161 } 1162 else { 1163 // Dummy element for drupal_render. Cleaner than adding a check in the theme function. 1164 $form[$info->name]['operations'] = array(); 1165 } 1166 } 1167 1168 $form['status'] = array('#type' => 'checkboxes', '#options' => $options, '#default_value' => $status); 1169 $form['theme_default'] = array('#type' => 'radios', '#options' => $options, '#default_value' => variable_get('theme_default', 'garland')); 1170 $form['buttons']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration') ); 1171 $form['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset to defaults') ); 1172 1173 return $form; 1174 } 1175 1176 function theme_system_themes($form) { 1177 foreach (element_children($form) as $key) { 1178 $row = array(); 1179 if (is_array($form[$key]['description'])) { 1180 $row[] = drupal_render($form[$key]['screenshot']); 1181 $row[] = drupal_render($form[$key]['description']); 1182 $row[] = array('data' => drupal_render($form['status'][$key]), 'align' => 'center'); 1183 if ($form['theme_default']) { 1184 $row[] = array('data' => drupal_render($form['theme_default'][$key]), 'align' => 'center'); 1185 $row[] = array('data' => drupal_render($form[$key]['operations']), 'align' => 'center'); 1186 } 1187 } 1188 $rows[] = $row; 1189 } 1190 1191 $header = array(t('Screenshot'), t('Name'), t('Enabled'), t('Default'), t('Operations')); 1192 $output = theme('table', $header, $rows); 1193 $output .= drupal_render($form); 1194 return $output; 1195 } 1196 1197 1198 function system_themes_submit($form_id, $form_values) { 1199 1200 db_query("UPDATE {system} SET status = 0 WHERE type = 'theme'"); 1201 1202 if ($form_values['op'] == t('Save configuration')) { 1203 if (is_array($form_values['status'])) { 1204 foreach ($form_values['status'] as $key => $choice) { 1205 // Always enable the default theme, despite its status checkbox being checked: 1206 if ($choice || $form_values['theme_default'] == $key) { 1207 system_initialize_theme_blocks($key); 1208 db_query("UPDATE {system} SET status = 1 WHERE type = 'theme' and name = '%s'", $key); 1209 } 1210 } 1211 } 1212 if (($admin_theme = variable_get('admin_theme', '0')) != '0' && $admin_theme != $form_values['theme_default']) { 1213 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( 1214 '!admin_theme_page' => url('admin/settings/admin'), 1215 '%admin_theme' => $admin_theme, 1216 '%selected_theme' => $form_values['theme_default'], 1217 ))); 1218 } 1219 variable_set('theme_default', $form_values['theme_default']); 1220 } 1221 else { 1222 variable_del('theme_default'); 1223 db_query("UPDATE {system} SET status = 1 WHERE type = 'theme' AND name = 'garland'"); 1224 } 1225 1226 menu_rebuild(); 1227 drupal_set_message(t('The configuration options have been saved.')); 1228 return 'admin/build/themes'; 1229 } 1230 1231 /** 1232 * Menu callback; provides module enable/disable interface. 1233 * 1234 * Modules can be enabled or disabled and set for throttling if the throttle module is enabled. 1235 * The list of modules gets populated by module.info files, which contain each module's name, 1236 * description and dependencies. 1237 * @see _module_parse_info_file for information on module.info descriptors. 1238 * 1239 * Dependency checking is performed to ensure that a module cannot be enabled if the module has 1240 * disabled dependencies and also to ensure that the module cannot be disabled if the module has 1241 * enabled dependents. 1242 * 1243 * @return 1244 * The form array. 1245 */ 1246 function system_modules($form_values = NULL) { 1247 // Get current list of modules. 1248 $files = module_rebuild_cache(); 1249 if ($confirm_form = system_modules_confirm_form($files, $form_values)) { 1250 return $confirm_form; 1251 } 1252 1253 // Store module list for validation callback. 1254 $form['validation_modules'] = array('#type' => 'value', '#value' => $files); 1255 1256 // Create storage for disabled modules as browser will disable checkboxes. 1257 $form['disabled_modules'] = array('#type' => 'value', '#value' => array()); 1258 1259 // Array for disabling checkboxes in callback system_module_disable. 1260 $disabled = array(); 1261 // Traverse the files retrieved and build the form. 1262 foreach ($files as $filename => $file) { 1263 $form['name'][$filename] = array('#value' => $file->info['name']); 1264 $form['version'][$filename] = array('#value' => $file->info['version']); 1265 $form['description'][$filename] = array('#value' => t($file->info['description'])); 1266 $options[$filename] = ''; 1267 if ($file->status) { 1268 $status[] = $file->name; 1269 } 1270 if ($file->throttle) { 1271 $throttle[] = $file->name; 1272 } 1273 1274 $dependencies = array(); 1275 // Check for missing dependencies. 1276 if (is_array($file->info['dependencies'])) { 1277 foreach ($file->info['dependencies'] as $dependency) { 1278 if (!isset($files[$dependency]) || !$files[$dependency]->status) { 1279 if (isset($files[$dependency])) { 1280 $dependencies[] = $files[$dependency]->info['name'] . t(' (<span class="admin-disabled">disabled</span>)'); 1281 } 1282 else { 1283 $dependencies[] = drupal_ucfirst($dependency) . t(' (<span class="admin-missing">missing</span>)'); 1284 $disabled[] = $filename; 1285 $form['disabled_modules']['#value'][$filename] = FALSE; 1286 } 1287 } 1288 else { 1289 $dependencies[] = $files[$dependency]->info['name'] . t(' (<span class="admin-enabled">enabled</span>)'); 1290 } 1291 } 1292 1293 // Add text for dependencies. 1294 if (!empty($dependencies)) { 1295 $form['description'][$filename]['dependencies'] = array( 1296 '#value' => t('Depends on: !dependencies', array('!dependencies' => implode(', ', $dependencies))), 1297 '#prefix' => '<div class="admin-dependencies">', 1298 '#suffix' => '</div>', 1299 ); 1300 } 1301 } 1302 1303 // Mark dependents disabled so user can not remove modules being depended on. 1304 $dependents = array(); 1305 if (is_array($file->info['dependents'])) { 1306 foreach ($file->info['dependents'] as $dependent) { 1307 if ($files[$dependent]->status == 1) { 1308 $dependents[] = $files[$dependent]->info['name'] . t(' (<span class="admin-enabled">enabled</span>)'); 1309 $disabled[] = $filename; 1310 $form['disabled_modules']['#value'][$filename] = TRUE; 1311 } 1312 else { 1313 $dependents[] = $files[$dependent]->info['name'] . t(' (<span class="admin-disabled">disabled</span>)'); 1314 } 1315 } 1316 } 1317 1318 // Add text for enabled dependents. 1319 if (!empty($dependents)) { 1320 $form['description'][$filename]['required'] = array( 1321 '#value' => t('Required by: !required', array('!required' => implode(', ', $dependents))), 1322 '#prefix' => '<div class="admin-required">', 1323 '#suffix' => '</div>', 1324 ); 1325 } 1326 } 1327 1328 // Merge in required modules. 1329 $modules_required = array('block', 'filter', 'node', 'system', 'user', 'watchdog'); 1330 foreach ($modules_required as $required) { 1331 $disabled[] = $required; 1332 $form['disabled_modules']['#value'][$required] = TRUE; 1333 } 1334 1335 // Handle status checkboxes, including overriding 1336 // the generated checkboxes for required modules. 1337 $form['status'] = array( 1338 '#type' => 'checkboxes', 1339 '#default_value' => $status, 1340 '#options' => $options, 1341 '#process' => array( 1342 'expand_checkboxes' => array(), 1343 'system_modules_disable' => array($disabled), 1344 ), 1345 ); 1346 1347 // Handle throttle checkboxes, including overriding the 1348 // generated checkboxes for required modules. 1349 if (module_exists('throttle')) { 1350 $form['throttle'] = array( 1351 '#type' => 'checkboxes', 1352 '#default_value' => $throttle, 1353 '#options' => $options, 1354 '#process' => array( 1355 'expand_checkboxes' => array(), 1356 'system_modules_disable' => array(array_merge($modules_required, array('throttle'))), 1357 ), 1358 ); 1359 } 1360 1361 $form['buttons']['submit'] = array( 1362 '#type' => 'submit', 1363 '#value' => t('Save configuration'), 1364 ); 1365 $form['#multistep'] = TRUE; 1366 $form['#action'] = url('admin/build/modules/list/confirm'); 1367 1368 return $form; 1369 } 1370 1371 /** 1372 * Form process callback function to disable check boxes. 1373 */ 1374 function system_modules_disable($form, $edit, $disabled) { 1375 foreach ($disabled as $key) { 1376 $form[$key]['#attributes']['disabled'] = 'disabled'; 1377 } 1378 return $form; 1379 } 1380 1381 function system_modules_confirm_form($modules, $form_values = array()) { 1382 $form = array(); 1383 $items = array(); 1384 1385 // Check values for submitted dependency errors. 1386 if ($dependencies = system_module_build_dependencies($modules, $form_values)) { 1387 // preserve the already switched on modules 1388 foreach ($modules as $name => $module) { 1389 if ($module->status) { 1390 $form['status'][$name] = array('#type' => 'hidden', '#value' => 1); 1391 } 1392 } 1393 1394 $form['validation_modules'] = array('#type' => 'value', '#value' => $modules); 1395 $form['status']['#tree'] = TRUE; 1396 foreach ($dependencies as $name => $missing_dependencies) { 1397 $form['status'][$name] = array('#type' => 'hidden', '#value' => 1); 1398 foreach ($missing_dependencies as $k => $dependency) { 1399 $form['status'][$dependency] = array('#type' => 'hidden', '#value' => 1); 1400 $info = $modules[$dependency]->info; 1401 $missing_dependencies[$k] = $info['name'] ? $info['name'] : drupal_ucfirst($dependency); 1402 } 1403 $t_argument = array( 1404 '%module' => $modules[$name]->info['name'], 1405 '%dependencies' => implode(', ', $missing_dependencies), 1406 ); 1407 $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); 1408 } 1409 $form['text'] = array('#value' => theme('item_list', $items)); 1410 } 1411 1412 if ($form) { 1413 // Set some default form values 1414 $form = confirm_form( 1415 $form, 1416 t('Some required modules must be enabled'), 1417 'admin/build/modules', 1418 t('Would you like to continue with enabling the above?'), 1419 t('Continue'), 1420 t('Cancel')); 1421 return $form; 1422 } 1423 } 1424 1425 function system_module_build_dependencies($modules, $form_values) { 1426 static $dependencies; 1427 1428 if (!isset($dependencies) && isset($form_values)) { 1429 $dependencies = array(); 1430 foreach ($modules as $name => $module) { 1431 // If the module is disabled, will be switched on and it has dependencies. 1432 if (!$module->status && $form_values['status'][$name] && isset($module->info['dependencies'])) { 1433 foreach ($module->info['dependencies'] as $dependency) { 1434 if (!$form_values['status'][$dependency] && isset($modules[$dependency])) { 1435 if (!isset($dependencies[$name])) { 1436 $dependencies[$name] = array(); 1437 } 1438 $dependencies[$name][] = $dependency; 1439 } 1440 } 1441 } 1442 } 1443 } 1444 return $dependencies; 1445 } 1446 1447 /** 1448 * Submit callback; handles modules form submission. 1449 */ 1450 function system_modules_submit($form_id, $form_values) { 1451 include_once './includes/install.inc'; 1452 $new_modules = array(); 1453 1454 // Merge in disabled active modules since they should be enabled. 1455 // They don't appear because disabled checkboxes are not submitted 1456 // by browsers. 1457 $form_values['status'] = array_merge($form_values['status'], $form_values['disabled_modules']); 1458 1459 // Check values for dependency that we can't install. 1460 if ($dependencies = system_module_build_dependencies($form_values['validation_modules'], $form_values)) { 1461 // These are the modules that depend on existing modules. 1462 foreach (array_keys($dependencies) as $name) { 1463 $form_values['status'][$name] = 0; 1464 } 1465 } 1466 1467 $enable_modules = array(); 1468 $disable_modules = array(); 1469 foreach ($form_values['status'] as $key => $choice) { 1470 if ($choice) { 1471 if (drupal_get_installed_schema_version($key) == SCHEMA_UNINSTALLED) { 1472 $new_modules[] = $key; 1473 } 1474 else { 1475 $enable_modules[] = $key; 1476 } 1477 } 1478 else { 1479 $disable_modules[] = $key; 1480 } 1481 } 1482 1483 $old_module_list = module_list(); 1484 1485 if (!empty($enable_modules)) { 1486 module_enable($enable_modules); 1487 } 1488 if (!empty($disable_modules)) { 1489 module_disable($disable_modules); 1490 } 1491 1492 // Install new modules. 1493 foreach ($new_modules as $key => $module) { 1494 if (!drupal_check_module($module)) { 1495 unset($new_modules[$key]); 1496 } 1497 } 1498 drupal_install_modules($new_modules); 1499 1500 $current_module_list = module_list(TRUE, FALSE); 1501 1502 if (is_array($form_values['throttle'])) { 1503 foreach ($form_values['throttle'] as $key => $choice) { 1504 db_query("UPDATE {system} SET throttle = %d WHERE type = 'module' and name = '%s'", $choice ? 1 : 0, $key); 1505 } 1506 } 1507 1508 if ($old_module_list != $current_module_list) { 1509 menu_rebuild(); 1510 node_types_rebuild(); 1511 drupal_set_message(t('The configuration options have been saved.')); 1512 } 1513 1514 // If there where unmet dependencies and they haven't confirmed don't redirect. 1515 if ($dependencies && !isset($form_values['confirm'])) { 1516 return FALSE; 1517 } 1518 1519 drupal_clear_css_cache(); 1520 1521 return 'admin/build/modules'; 1522 } 1523 1524 /** 1525 * Theme call back for the modules form. 1526 */ 1527 function theme_system_modules($form) { 1528 if (isset($form['confirm'])) { 1529 return drupal_render($form); 1530 } 1531 1532 // Individual table headers. 1533 $header = array(t('Enabled')); 1534 if (module_exists('throttle')) { 1535 $header[] = t('Throttle'); 1536 } 1537 $header[] = t('Name'); 1538 $header[] = t('Version'); 1539 $header[] = t('Description'); 1540 1541 // Pull package information from module list and start grouping modules. 1542 $modules = $form['validation_modules']['#value']; 1543 foreach ($modules as $module) { 1544 if (!isset($module->info['package']) || !$module->info['package']) { 1545 $module->info['package'] = t('Other'); 1546 } 1547 $packages[$module->info['package']][$module->name] = $module->info; 1548 } 1549 ksort($packages); 1550 1551 // Display packages. 1552 $output = ''; 1553 foreach ($packages as $package => $modules) { 1554 $rows = array(); 1555 foreach ($modules as $key => $module) { 1556 $row = array(); 1557 $row[] = array('data' => drupal_render($form['status'][$key]), 'align' => 'center'); 1558 1559 if (module_exists('throttle')) { 1560 $row[] = array('data' => drupal_render($form['throttle'][$key]), 'align' => 'center'); 1561 } 1562 $row[] = '<strong>'. drupal_render($form['name'][$key]) .'</strong>'; 1563 $row[] = drupal_render($form['version'][$key]); 1564 $row[] = array('data' => drupal_render($form['description'][$key]), 'class' => 'description'); 1565 $rows[] = $row; 1566 } 1567 $fieldset = array( 1568 '#title' => t($package), 1569 '#collapsible' => TRUE, 1570 '#collapsed' => ($package == 'Core - required'), 1571 '#value' => theme('table', $header, $rows, array('class' => 'package')), 1572 ); 1573 $output .= theme('fieldset', $fieldset); 1574 } 1575 1576 $output .= drupal_render($form); 1577 return $output; 1578 } 1579 1580 /** 1581 * Uninstall functions 1582 */ 1583 1584 /** 1585 * Builds a form of currently disabled modules. 1586 * 1587 * @param 1588 * $form_values Submitted form values. 1589 * @return 1590 * A form array representing the currently disabled modules. 1591 */ 1592 function system_modules_uninstall($form_values = NULL) { 1593 // Make sure the install API is available. 1594 include_once './includes/install.inc'; 1595 1596 // Display the confirm form if any modules have been submitted. 1597 if ($confirm_form = system_modules_uninstall_confirm_form($form_values)) { 1598 return $confirm_form; 1599 } 1600 1601 $form = array(); 1602 1603 // Pull all disabled modules from the system table. 1604 $disabled_modules = db_query("SELECT name, filename FROM {system} WHERE type = 'module' AND status = 0 AND schema_version > %d ORDER BY name", SCHEMA_UNINSTALLED); 1605 while ($module = db_fetch_object($disabled_modules)) { 1606 1607 // Grab the .info file and set name and description. 1608 $info = _module_parse_info_file(dirname($module->filename) .'/'. $module->name .'.info'); 1609 1610 // Load the .install file, and check for an uninstall hook. 1611 // If the hook exists, the module can be uninstalled. 1612 module_load_install($module->name); 1613 if (module_hook($module->name, 'uninstall')) { 1614 $form['modules'][$module->name]['name'] = array('#value' => $info['name'] ? $info['name'] : $module->name); 1615 $form['modules'][$module->name]['description'] = array('#value' => t($info['description'])); 1616 $options[$module->name] = ''; 1617 } 1618 } 1619 1620 // Only build the rest of the form if there are any modules available to uninstall. 1621 if (count($options)) { 1622 $form['uninstall'] = array( 1623 '#type' => 'checkboxes', 1624 '#options' => $options, 1625 ); 1626 $form['buttons']['submit'] = array( 1627 '#type' => 'button', 1628 '#value' => t('Uninstall'), 1629 ); 1630 $form['#multistep'] = TRUE; 1631 $form['#action'] = url('admin/build/modules/uninstall/confirm'); 1632 } 1633 1634 return $form; 1635 } 1636 1637 /** 1638 * Confirm uninstall of selected modules. 1639 * 1640 * @param 1641 * $form_values Submitted form values. 1642 * @return 1643 * A form array representing modules to confirm. 1644 */ 1645 function system_modules_uninstall_confirm_form($form_values) { 1646 // Nothing to build. 1647 if (!isset($form_values)) { 1648 return; 1649 } 1650 1651 // Construct the hidden form elements and list items. 1652 foreach (array_filter($form_values['uninstall']) as $module => $value) { 1653 $info = _module_parse_info_file(dirname(drupal_get_filename('module', $module)) .'/'. $module .'.info'); 1654 $uninstall[] = $info['name']; 1655 $form['uninstall'][$module] = array('#type' => 'hidden', 1656 '#value' => 1, 1657 ); 1658 } 1659 1660 // Display a confirm form if modules have been selected. 1661 if (isset($uninstall)) { 1662 $form['uninstall']['#tree'] = TRUE; 1663 $form['#multistep'] = TRUE; 1664 $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)); 1665 $form = confirm_form( 1666 $form, 1667 t('Confirm uninstall'), 1668 'admin/build/modules/uninstall', 1669 t('Would you like to continue with uninstalling the above?'), 1670 t('Uninstall'), 1671 t('Cancel')); 1672 return $form; 1673 } 1674 } 1675 1676 /** 1677 * Themes a table of currently disabled modules. 1678 * 1679 * @param 1680 * $form The form array representing the currently disabled modules. 1681 * @return 1682 * An HTML string representing the table. 1683 */ 1684 function theme_system_modules_uninstall($form) { 1685 // No theming for the confirm form. 1686 if (isset($form['confirm'])) { 1687 return drupal_render($form); 1688 } 1689 1690 // Table headers. 1691 $header = array(t('Uninstall'), 1692 t('Name'), 1693 t('Description'), 1694 ); 1695 1696 // Display table. 1697 $rows = array(); 1698 foreach (element_children($form['modules']) as $module) { 1699 $rows[] = array( 1700 array('data' => drupal_render($form['uninstall'][$module]), 'align' => 'center'), 1701 '<strong>'. drupal_render($form['modules'][$module]['name']) .'</strong>', 1702 array('data' => drupal_render($form['modules'][$module]['description']), 'class' => 'description'), 1703 ); 1704 } 1705 1706 // Only display table if there are modules that can be uninstalled. 1707 if (!count($rows)) { 1708 $rows[] = array(array('data' => t('No modules are available to uninstall.'), 'colspan' => '3', 'align' => 'center', 'class' => 'message')); 1709 } 1710 1711 $output = theme('table', $header, $rows); 1712 $output .= drupal_render($form); 1713 1714 return $output; 1715 } 1716 1717 /** 1718 * Validates the submitted uninstall form. 1719 * 1720 * @param 1721 * $form_id The form ID. 1722 * @param 1723 * $form_values Submitted form values. 1724 */ 1725 function system_modules_uninstall_validate($form_id, $form_values) { 1726 // Form submitted, but no modules selected. 1727 if (!count(array_filter($form_values['uninstall']))) { 1728 drupal_set_message(t('No modules selected.'), 'error'); 1729 drupal_goto('admin/build/modules/uninstall'); 1730 } 1731 } 1732 1733 /** 1734 * Processes the submitted uninstall form. 1735 * 1736 * @param 1737 * $form_id The form ID. 1738 * @param 1739 * $form_values Submitted form values. 1740 */ 1741 function system_modules_uninstall_submit($form_id, $form_values) { 1742 // Make sure the install API is available. 1743 include_once './includes/install.inc'; 1744 1745 // Call the uninstall routine for each selected module. 1746 foreach (array_filter($form_values['uninstall']) as $module => $value) { 1747 drupal_uninstall_module($module); 1748 } 1749 drupal_set_message(t('The selected modules have been uninstalled.')); 1750 drupal_goto('admin/build/modules/uninstall'); 1751 } 1752 1753 /** 1754 * Menu callback: run cron manually. 1755 */ 1756 function system_run_cron() { 1757 // Run cron manually 1758 if (drupal_cron_run()) { 1759 drupal_set_message(t('Cron ran successfully')); 1760 } 1761 else { 1762 drupal_set_message(t('Cron run failed')); 1763 } 1764 1765 drupal_goto('admin/logs/status'); 1766 } 1767 1768 /** 1769 * Menu callback: return information about PHP. 1770 */ 1771 function system_php() { 1772 phpinfo(INFO_GENERAL | INFO_CONFIGURATION); 1773 exit(); 1774 } 1775 1776 function _system_sql($data, $keys) { 1777 $rows = array(); 1778 foreach ($keys as $key => $explanation) { 1779 if (isset($data[$key])) { 1780 $rows[] = array(check_plain($key), check_plain($data[$key]), $explanation); 1781 } 1782 } 1783 1784 return theme('table', array(t('Variable'), t('Value'), t('Description')), $rows); 1785 } 1786 1787 /** 1788 * Menu callback: return information about PHP. 1789 */ 1790 function system_sql() { 1791 1792 $result = db_query("SHOW STATUS"); 1793 while ($entry = db_fetch_object($result)) { 1794 $data[$entry->Variable_name] = $entry->Value; 1795 } 1796 1797 $output = '<h2>'. t('Command counters') .'</h2>'; 1798 $output .= _system_sql($data, array( 1799 'Com_select' => t('The number of <code>SELECT</code>-statements.'), 1800 'Com_insert' => t('The number of <code>INSERT</code>-statements.'), 1801 'Com_update' => t('The number of <code>UPDATE</code>-statements.'), 1802 'Com_delete' => t('The number of <code>DELETE</code>-statements.'), 1803 'Com_lock_tables' => t('The number of table locks.'), 1804 'Com_unlock_tables' => t('The number of table unlocks.') 1805 )); 1806 1807 $output .= '<h2>'. t('Query performance') .'</h2>'; 1808 $output .= _system_sql($data, array( 1809 'Select_full_join' => t('The number of joins without an index; should be zero.'), 1810 'Select_range_check' => t('The number of joins without an index; should be zero.'), 1811 'Sort_scan' => t('The number of sorts done without using an index; should be zero.'), 1812 'Table_locks_immediate' => t('The number of times a lock could be acquired immediately.'), 1813 'Table_locks_waited' => t('The number of times the server had to wait for a lock.') 1814 )); 1815 1816 $output .= '<h2>'. t('Query cache information') .'</h2>'; 1817 $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>'; 1818 $output .= _system_sql($data, array( 1819 'Qcache_queries_in_cache' => t('The number of queries in the query cache.'), 1820 'Qcache_hits' => t('The number of times that MySQL found previous results in the cache.'), 1821 'Qcache_inserts' => t('The number of times that MySQL added a query to the cache (misses).'), 1822 '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.') 1823 )); 1824 1825 return $output; 1826 } 1827 1828 /** 1829 * Menu callback: displays the site status report. Can also be used as a pure check. 1830 * 1831 * @param $check 1832 * If true, only returns a boolean whether there are system status errors. 1833 */ 1834 function system_status($check = FALSE) { 1835 // Load .install files 1836 include_once './includes/install.inc'; 1837 drupal_load_updates(); 1838 1839 // Check run-time requirements and status information 1840 $requirements = module_invoke_all('requirements', 'runtime'); 1841 usort($requirements, '_system_sort_requirements'); 1842 1843 if ($check) { 1844 return drupal_requirements_severity($requirements) == REQUIREMENT_ERROR; 1845 } 1846 1847 return theme('status_report', $requirements); 1848 } 1849 1850 /** 1851 * Helper function to sort requirements. 1852 */ 1853 function _system_sort_requirements($a, $b) { 1854 return (isset($a['weight']) || isset($b['weight'])) ? $a['weight'] - $b['weight'] : strcmp($a['title'], $b['title']); 1855 } 1856 1857 /** 1858 * Theme status report 1859 */ 1860 function theme_status_report(&$requirements) { 1861 $i = 0; 1862 $output = '<table class="system-status-report">'; 1863 foreach ($requirements as $requirement) { 1864 if ($requirement['#type'] == '') { 1865 $class = ++$i % 2 == 0 ? 'even' : 'odd'; 1866 1867 $classes = array( 1868 REQUIREMENT_INFO => 'info', 1869 REQUIREMENT_OK => 'ok', 1870 REQUIREMENT_WARNING => 'warning', 1871 REQUIREMENT_ERROR => 'error', 1872 ); 1873 $class = $classes[(int)$requirement['severity']] .' '. $class; 1874 1875 // Output table row(s) 1876 if ($requirement['description']) { 1877 $output .= '<tr class="'. $class .' merge-down"><th>'. $requirement['title'] .'</th><td>'. $requirement['value'] .'</td></tr>'; 1878 $output .= '<tr class="'. $class .' merge-up"><td colspan="2">'. $requirement['description'] .'</td></tr>'; 1879 } 1880 else { 1881 $output .= '<tr class="'. $class .'"><th>'. $requirement['title'] .'</th><td>'. $requirement['value'] .'</td></tr>'; 1882 } 1883 } 1884 } 1885 1886 $output .= '</table>'; 1887 return $output; 1888 } 1889 1890 /** 1891 * Menu callback; displays a module's settings page. 1892 */ 1893 function system_settings_overview() { 1894 1895 // Check database setup if necessary 1896 if (function_exists('db_check_setup') && empty($_POST)) { 1897 db_check_setup(); 1898 } 1899 1900 $menu = menu_get_item(NULL, 'admin/settings'); 1901 $content = system_admin_menu_block($menu); 1902 1903 $output = theme('admin_block_content', $content); 1904 1905 return $output; 1906 } 1907 1908 /** 1909 * Menu callback; display theme configuration for entire site and individual themes. 1910 */ 1911 function system_theme_settings($key = '') { 1912 $directory_path = file_directory_path(); 1913 file_check_directory($directory_path, FILE_CREATE_DIRECTORY, 'file_directory_path'); 1914 1915 // Default settings are defined in theme_get_settings() in includes/theme.inc 1916 if ($key) { 1917 $settings = theme_get_settings($key); 1918 $var = str_replace('/', '_', 'theme_'. $key .'_settings'); 1919 $themes = system_theme_data(); 1920 $features = function_exists($themes[$key]->prefix .'_features') ? call_user_func($themes[$key]->prefix .'_features') : array(); 1921 } 1922 else { 1923 $settings = theme_get_settings(''); 1924 $var = 'theme_settings'; 1925 } 1926 1927 $form['var'] = array('#type' => 'hidden', '#value' => $var); 1928 1929 // Check for a new uploaded logo, and use that instead. 1930 if ($file = file_check_upload('logo_upload')) { 1931 if ($info = image_get_info($file->filepath)) { 1932 $parts = pathinfo($file->filename); 1933 $filename = ($key) ? str_replace('/', '_', $key) .'_logo.'. $parts['extension'] : 'logo.'. $parts['extension']; 1934 1935 if ($file = file_save_upload('logo_upload', $filename, 1)) { 1936 $_POST['default_logo'] = 0; 1937 $_POST['logo_path'] = $file->filepath; 1938 $_POST['toggle_logo'] = 1; 1939 } 1940 } 1941 else { 1942 form_set_error('file_upload', t('Only JPEG, PNG and GIF images are allowed to be used as logos.')); 1943 } 1944 } 1945 1946 // Check for a new uploaded favicon, and use that instead. 1947 if ($file = file_check_upload('favicon_upload')) { 1948 $parts = pathinfo($file->filename); 1949 $filename = ($key) ? str_replace('/', '_', $key) .'_favicon.'. $parts['extension'] : 'favicon.'. $parts['extension']; 1950 1951 if ($file = file_save_upload('favicon_upload', $filename, 1)) { 1952 $_POST['default_favicon'] = 0; 1953 $_POST['favicon_path'] = $file->filepath; 1954 $_POST['toggle_favicon'] = 1; 1955 } 1956 } 1957 1958 // Toggle settings 1959 $toggles = array( 1960 'toggle_logo' => t('Logo'), 1961 'toggle_name' => t('Site name'), 1962 'toggle_slogan' => t('Site slogan'), 1963 'toggle_mission' => t('Mission statement'), 1964 'toggle_node_user_picture' => t('User pictures in posts'), 1965 'toggle_comment_user_picture' => t('User pictures in comments'), 1966 'toggle_search' => t('Search box'), 1967 'toggle_favicon' => t('Shortcut icon') 1968 ); 1969 1970 // Some features are not always available 1971 $disabled = array(); 1972 if (!variable_get('user_pictures', 0)) { 1973 $disabled['toggle_node_user_picture'] = TRUE; 1974 $disabled['toggle_comment_user_picture'] = TRUE; 1975 } 1976 if (!module_exists('search')) { 1977 $disabled['toggle_search'] = TRUE; 1978 } 1979 1980 $form['theme_settings'] = array( 1981 '#type' => 'fieldset', 1982 '#title' => t('Toggle display'), 1983 '#description' => t('Enable or disable the display of certain page elements.'), 1984 ); 1985 foreach ($toggles as $name => $title) { 1986 if ((!$key) || in_array($name, $features)) { 1987 // disable search box if search.module is disabled 1988 $form['theme_settings'][$name] = array('#type' => 'checkbox', '#title' => $title, '#default_value' => $settings[$name]); 1989 if (isset($disabled[$name])) { 1990 $form['theme_settings'][$name]['#disabled'] = TRUE; 1991 } 1992 } 1993 } 1994 1995 // System wide only settings. 1996 if (!$key) { 1997 // Create neat 2-column layout for the toggles 1998 $form['theme_settings'] += array( 1999 '#prefix' => '<div class="theme-settings-left">', 2000 '#suffix' => '</div>', 2001 ); 2002 2003 // Toggle node display. 2004 $node_types = node_get_types('names'); 2005 if ($node_types) { 2006 $form['node_info'] = array( 2007 '#type' => 'fieldset', 2008 '#title' => t('Display post information on'), 2009 '#description' => t('Enable or disable the <em>submitted by Username on date</em> text when displaying posts of the following type.'), 2010 '#prefix' => '<div class="theme-settings-right">', 2011 '#suffix' => '</div>', 2012 ); 2013 foreach ($node_types as $type => $name) { 2014 $form['node_info']["toggle_node_info_$type"] = array('#type' => 'checkbox', '#title' => check_plain($name), '#default_value' => $settings["toggle_node_info_$type"]); 2015 } 2016 } 2017 } 2018 2019 // Logo settings 2020 if ((!$key) || in_array('toggle_logo', $features)) { 2021 $form['logo'] = array( 2022 '#type' => 'fieldset', 2023 '#title' => t('Logo image settings'), 2024 '#description' => t('If toggled on, the following logo will be displayed.'), 2025 '#attributes' => array('class' => 'theme-settings-bottom'), 2026 ); 2027 $form['logo']["default_logo"] = array( 2028 '#type' => 'checkbox', 2029 '#title' => t('Use the default logo'), 2030 '#default_value' => $settings['default_logo'], 2031 '#tree' => FALSE, 2032 '#description' => t('Check here if you want the theme to use the logo supplied with it.') 2033 ); 2034 $form['logo']['logo_path'] = array( 2035 '#type' => 'textfield', 2036 '#title' => t('Path to custom logo'), 2037 '#default_value' => $settings['logo_path'], 2038 '#description' => t('The path to the file you would like to use as your logo file instead of the default logo.')); 2039 2040 $form['logo']['logo_upload'] = array( 2041 '#type' => 'file', 2042 '#title' => t('Upload logo image'), 2043 '#maxlength' => 40, 2044 '#description' => t("If you don't have direct file access to the server, use this field to upload your logo.") 2045 ); 2046 } 2047 2048 // Icon settings 2049 if ((!$key) || in_array('toggle_favicon', $features)) { 2050 $form['favicon'] = array( 2051 '#type' => 'fieldset', 2052 '#title' => t('Shortcut icon settings'), 2053 '#description' => t("Your shortcut icon or 'favicon' is displayed in the address bar and bookmarks of most browsers.") 2054 ); 2055 $form['favicon']['default_favicon'] = array( 2056 '#type' => 'checkbox', 2057 '#title' => t('Use the default shortcut icon.'), 2058 '#default_value' => $settings['default_favicon'], 2059 '#description' => t('Check here if you want the theme to use the default shortcut icon.') 2060 ); 2061 $form['favicon']['favicon_path'] = array( 2062 '#type' => 'textfield', 2063 '#title' => t('Path to custom icon'), 2064 '#default_value' => $settings['favicon_path'], 2065 '#description' => t('The path to the image file you would like to use as your custom shortcut icon.') 2066 ); 2067 2068 $form['favicon']['favicon_upload'] = array( 2069 '#type' => 'file', 2070 '#title' => t('Upload icon image'), 2071 '#description' => t("If you don't have direct file access to the server, use this field to upload your shortcut icon.") 2072 ); 2073 } 2074 2075 if ($key) { 2076 // Template-specific settings 2077 $function = $themes[$key]->prefix .'_settings'; 2078 if (function_exists($function)) { 2079 if ($themes[$key]->template) { 2080 // file is a template or a style of a template 2081 $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))); 2082 } 2083 else { 2084 // file is a theme or a style of a theme 2085 $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))); 2086 } 2087 $group = $function(); 2088 $form['specific'] = array_merge($form['specific'], (is_array($group) ? $group : array())); 2089 } 2090 } 2091 $form['#attributes'] = array('enctype' => 'multipart/form-data'); 2092 2093 return system_settings_form($form); 2094 } 2095 2096 /** 2097 * Implementation of hook_node_type(). 2098 * 2099 * Updates theme settings after a node type change. 2100 */ 2101 function system_node_type($op, $info) { 2102 if ($op == 'update' && !empty($info->old_type) && $info->type != $info->old_type) { 2103 $old = 'toggle_node_info_'. $info->old_type; 2104 $new = 'toggle_node_info_'. $info->type; 2105 2106 $theme_settings = variable_get('theme_settings', array()); 2107 if (isset($theme_settings[$old])) { 2108 $theme_settings[$new] = $theme_settings[$old]; 2109 unset($theme_settings[$old]); 2110 variable_set('theme_settings', $theme_settings); 2111 } 2112 } 2113 } 2114 2115 /** 2116 * Output a confirmation form 2117 * 2118 * This function returns a complete form for confirming an action. A link is 2119 * offered to go back to the item that is being changed in case the user 2120 * changes his/her mind. 2121 * 2122 * If the submit handler for this form is invoked, the user successfully 2123 * confirmed the action. You should never directly inspect $_POST to see if an 2124 * action was confirmed. 2125 * 2126 * @param $form 2127 * Additional elements to inject into the form, for example hidden elements. 2128 * @param $question 2129 * The question to ask the user (e.g. "Are you sure you want to delete the 2130 * block <em>foo</em>?"). 2131 * @param $path 2132 * The page to go to if the user denies the action. 2133 * Can be either a drupal path, or an array with the keys 'path', 'query', 'fragment'. 2134 * @param $description 2135 * Additional text to display (defaults to "This action cannot be undone."). 2136 * @param $yes 2137 * A caption for the button which confirms the action (e.g. "Delete", 2138 * "Replace", ...). 2139 * @param $no 2140 * A caption for the link which denies the action (e.g. "Cancel"). 2141 * @param $name 2142 * The internal name used to refer to the confirmation item. 2143 * @return 2144 * The form. 2145 */ 2146 function confirm_form($form, $question, $path, $description = NULL, $yes = NULL, $no = NULL, $name = 'confirm') { 2147 $description = isset($description) ? $description : t('This action cannot be undone.'); 2148 2149 // Prepare cancel link 2150 $query = $fragment = NULL; 2151 if (is_array($path)) { 2152 $query = isset($path['query']) ? $path['query'] : NULL; 2153 $fragment = isset($path['fragment']) ? $path['fragment'] : NULL; 2154 $path = isset($path['path']) ? $path['path'] : NULL; 2155 } 2156 $cancel = l($no ? $no : t('Cancel'), $path, array(), $query, $fragment); 2157 2158 drupal_set_title($question); 2159 2160 $form['#attributes'] = array('class' => 'confirmation'); 2161 $form['description'] = array('#value' => $description); 2162 $form[$name] = array('#type' => 'hidden', '#value' => 1); 2163 2164 $form['actions'] = array('#prefix' => '<div class="container-inline">', '#suffix' => '</div>'); 2165 $form['actions']['submit'] = array('#type' => 'submit', '#value' => $yes ? $yes : t('Confirm')); 2166 $form['actions']['cancel'] = array('#value' => $cancel); 2167 $form['#base'] = 'confirm_form'; 2168 return $form; 2169 } 2170 2171 /** 2172 * Determine if a user is in compact mode. 2173 */ 2174 function system_admin_compact_mode() { 2175 global $user; 2176 return (isset($user->admin_compact_mode)) ? $user->admin_compact_mode : variable_get('admin_compact_mode', FALSE); 2177 } 2178 2179 /** 2180 * This function formats an administrative page for viewing. 2181 * 2182 * @param $blocks 2183 * An array of blocks to display. Each array should include a 2184 * 'title', a 'description', a formatted 'content' and a 2185 * 'position' which will control which container it will be 2186 * in. This is usually 'left' or 'right'. 2187 * @themeable 2188 */ 2189 function theme_admin_page($blocks) { 2190 $stripe = 0; 2191 $container = array(); 2192 2193 foreach ($blocks as $block) { 2194 if ($block_output = theme('admin_block', $block)) { 2195 if (!$block['position']) { 2196 // perform automatic striping. 2197 $block['position'] = $stripe++ % 2 ? 'left' : 'right'; 2198 } 2199 $container[$block['position']] .= $block_output; 2200 } 2201 } 2202 2203 $output = '<div class="admin clear-block">'; 2204 $output .= '<div class="compact-link">'; 2205 if (system_admin_compact_mode()) { 2206 $output .= l(t('Show descriptions'), 'admin/compact/off', array('title' => t('Produce a less compact layout that includes descriptions.'))); 2207 } 2208 else { 2209 $output .= l(t('Hide descriptions'), 'admin/compact/on', array('title' => t("Produce a more compact layout that doesn't include descriptions."))); 2210 } 2211 $output .= '</div>'; 2212 2213 foreach ($container as $id => $data) { 2214 $output .= '<div class="'. $id .' clear-block">'; 2215 $output .= $data; 2216 $output .= '</div>'; 2217 } 2218 $output .= '</div>'; 2219 return $output; 2220 } 2221 2222 /** 2223 * This function formats an administrative block for display. 2224 * 2225 * @param $block 2226 * An array containing information about the block. It should 2227 * include a 'title', a 'description' and a formatted 'content'. 2228 * @themeable 2229 */ 2230 function theme_admin_block($block) { 2231 // Don't display the block if it has no content to display. 2232 if (!$block['content']) { 2233 return ''; 2234 } 2235 2236 $output = <<< EOT 2237 <div class="admin-panel"> 2238 <h3> 2239 $block[title] 2240 </h3> 2241 <div class="body"> 2242 <p class="description"> 2243 $block[description] 2244 </p> 2245 $block[content] 2246 </div> 2247 </div> 2248 EOT; 2249 return $output; 2250 } 2251 2252 /** 2253 * This function formats the content of an administrative block. 2254 * 2255 * @param $block 2256 * An array containing information about the block. It should 2257 * include a 'title', a 'description' and a formatted 'content'. 2258 * @themeable 2259 */ 2260 function theme_admin_block_content($content) { 2261 if (!$content) { 2262 return ''; 2263 } 2264 2265 if (system_admin_compact_mode()) { 2266 $output = '<ul class="menu">'; 2267 foreach ($content as $item) { 2268 $output .= '<li class="leaf">'. l($item['title'], $item['path'], array('title' => $item['description'])) .'</li>'; 2269 } 2270 $output .= '</ul>'; 2271 } 2272 else { 2273 $output = '<dl class="admin-list">'; 2274 foreach ($content as $item) { 2275 $output .= '<dt>'. l($item['title'], $item['path']) .'</dt>'; 2276 $output .= '<dd>'. $item['description'] .'</dd>'; 2277 } 2278 $output .= '</dl>'; 2279 } 2280 return $output; 2281 } 2282 2283 /** 2284 * Menu callback; prints a listing of admin tasks for each installed module. 2285 */ 2286 function system_admin_by_module() { 2287 $modules = module_rebuild_cache(); 2288 $menu_items = array(); 2289 foreach ($modules as $file) { 2290 $module = $file->name; 2291 if ($module == 'help') { 2292 continue; 2293 } 2294 2295 $admin_tasks = system_get_module_admin_tasks($module); 2296 2297 // Only display a section if there are any available tasks. 2298 if (count($admin_tasks)) { 2299 2300 // Check for help links. 2301 if (module_invoke($module, 'help', "admin/help#$module")) { 2302 $admin_tasks[100] = l(t('Get help'), "admin/help/$module"); 2303 } 2304 2305 // Sort. 2306 ksort($admin_tasks); 2307 2308 $menu_items[$file->info['name']] = array($file->info['description'], $admin_tasks); 2309 } 2310 } 2311 return theme('system_admin_by_module', $menu_items); 2312 } 2313 2314 function system_get_module_admin_tasks($module) { 2315 $admin_access = user_access('administer access control'); 2316 $menu = menu_get_menu(); 2317 $admin_tasks = array(); 2318 2319 // Check for permissions. 2320 if (module_hook($module, 'perm') && $admin_access) { 2321 $admin_tasks[-1] = l(t('Configure permissions'), 'admin/user/access', NULL, NULL, 'module-'. $module); 2322 } 2323 2324 // Check for menu items that are admin links. 2325 if ($items = module_invoke($module, 'menu', TRUE)) { 2326 foreach ($items as $item) { 2327 $parts = explode('/', $item['path']); 2328 $n = count($parts); 2329 if ((!isset($item['type']) || ($item['type'] & MENU_VISIBLE_IN_TREE)) && ($parts[0] == 'admin') && ($n >= 3) && _menu_item_is_accessible($menu['path index'][$item['path']])) { 2330 $admin_tasks[$item['title']] = l($item['title'], $item['path']); 2331 } 2332 } 2333 } 2334 2335 return $admin_tasks; 2336 } 2337 2338 /** 2339 * Theme output of the dashboard page. 2340 */ 2341 function theme_system_admin_by_module($menu_items) { 2342 $stripe = 0; 2343 $output = ''; 2344 $container = array(); 2345 2346 // Iterate over all modules 2347 foreach ($menu_items as $module => $block) { 2348 list($description, $items) = $block; 2349 2350 // Output links 2351 if (count($items)) { 2352 $block = array(); 2353 $block['title'] = $module; 2354 $block['content'] = theme('item_list', $items); 2355 $block['description'] = t($description); 2356 2357 if ($block_output = theme('admin_block', $block)) { 2358 if (!$block['position']) { 2359 // Perform automatic striping. 2360 $block['position'] = ++$stripe % 2 ? 'left' : 'right'; 2361 } 2362 $container[$block['position']] .= $block_output; 2363 } 2364 } 2365 } 2366 2367 $output = '<div class="admin">'; 2368 foreach ($container as $id => $data) { 2369 $output .= '<div class="'. $id .' clear-block">'; 2370 $output .= $data; 2371 $output .= '</div>'; 2372 } 2373 $output .= '</div>'; 2374 2375 return $output; 2376 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Fri Nov 30 16:20:15 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |