system.module 64.7 KB
Newer Older
Dries's avatar
 
Dries committed
1
<?php
2
// $Id$
Dries's avatar
 
Dries committed
3

Dries's avatar
   
Dries committed
4
5
6
7
8
/**
 * @file
 * Configuration system that lets administrators modify the workings of the site.
 */

9
define('VERSION', '6.0-dev');
10
define('DRUPAL_CORE_COMPATIBILITY', '6.x');
11

12
13
14
15
16
define('DRUPAL_MINIMUM_PHP',    '4.3.3');
define('DRUPAL_MINIMUM_MYSQL',  '4.1.0'); // If using MySQL
define('DRUPAL_MINIMUM_PGSQL',  '7.4');   // If using PostgreSQL
define('DRUPAL_MINIMUM_APACHE', '1.3');   // If using Apache

17
18
19
// Maximum age of temporary files in seconds.
define('DRUPAL_MAXIMUM_TEMP_FILE_AGE', 1440);

Dries's avatar
   
Dries committed
20
21
22
/**
 * Implementation of hook_help().
 */
23
function system_help($path, $arg) {
24
25
  global $base_url;

26
  switch ($path) {
27
    case 'admin/help#system':
28
      $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 website 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 website performance. The system module provides control over preferences, behaviors including visual and operational settings.') .'</p>';
29
      $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>';
30
      $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>';
31
      $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>';
32
      return $output;
33
    case 'admin':
34
      return '<p>'. t('Welcome to the administration section. Here you may control how your site functions.') .'</p>';
35
    case 'admin/by-module':
36
      return '<p>'. t('This page shows you all available administration tasks for each module.') .'</p>';
37
    case 'admin/build/themes':
38
      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>';
39
40
    case 'admin/build/themes/settings/'. $arg[4]:
      $reference = explode('.', $arg[4], 2);
41
      $theme = array_pop($reference);
42
      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>';
43
44
    case 'admin/build/themes/settings':
      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>';
45
    case 'admin/build/modules':
46
      $output = '<p>'. t('Modules are plugins for Drupal that extend its core functionality. Here you can select which modules are enabled. 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.', array('@permissions' => url('admin/user/permissions')));
47
48
49
50
51
52
      if (module_exists('throttle')) {
        $output .= ' '. t('The auto-throttle functionality must be enabled on the <a href="@throttle">throttle configuration page</a> after having enabled the throttle module.', array('@throttle' => url('admin/settings/throttle')));
      }
      $output .= '</p>';
      $output .= t('<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('@update-php' => $base_url .'/update.php', '@by-module' => url('admin/by-module')));
      return $output;
53
    case 'admin/build/modules/uninstall':
54
      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>';
55
56
57
58
    case 'admin/build/block/configure':
      if ($arg[4] == 'system' && $arg[5] == 0) {
        return '<p>'. t('The <em>Powered by Drupal</em> block is an optional link to the home page of the Drupal project. While there is absolutely no requirement that sites feature this link, it may be used to show support for Drupal.') .'</p>';
      }
59
      break;
60
61
62
63
64
65
66
    case 'admin/settings/actions':
    case 'admin/settings/actions/manage':
      $output = '<p>'. t('Actions are individual tasks that the system can do, such as unpublishing a piece of content or banning a user. Modules, such as the trigger module, can fire these actions when certain system events happen; for example, when a new post is added or when a user logs in. Modules may also provide additional actions.') .'</p>';
      $output .= '<p>'. t('There are two types of actions: simple and advanced. Simple actions do not require any additional configuration, and are listed here automatically. Advanced actions can do more than simple actions; for example, send an e-mail to a specified address, or check for certain words within a piece of content. These actions need to be created and configured first before they may be used. To create an advanced action, select the action from the drop-down below and click the <em>Create</em> button.') .'</p>';
      if (module_exists('trigger')) {
        $output .= '<p>'. t('You may proceed to the <a href="@url">Triggers</a> page to assign these actions to system events.', array('@url' => url('admin/build/trigger'))) .'</p>';
      }
67
      return $output;
68
69
    case 'admin/settings/actions/configure':
      return t('An advanced action offers additional configuration options which may be filled out below. Changing the <em>Description</em> field is recommended, in order to better identify the precise action taking place. This description will be displayed in modules such as the trigger module when assigning actions to system events, so it is best if it is as descriptive as possible (for example, "Send e-mail to Moderation Team" rather than simply "Send e-mail").');
70
    case 'admin/reports/status':
71
      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>';
72
  }
Dries's avatar
   
Dries committed
73
74
}

75
76
77
78
function system_theme() {
  return array_merge(drupal_common_themes(), array(
    'system_theme_select_form' => array(
      'arguments' => array('form' => NULL),
79
      'file' => 'system.admin.inc',
80
81
82
    ),
    'system_themes_form' => array(
      'arguments' => array('form' => NULL),
83
      'file' => 'system.admin.inc',
84
85
86
    ),
    'system_modules' => array(
      'arguments' => array('form' => NULL),
87
      'file' => 'system.admin.inc',
88
89
90
    ),
    'system_modules_uninstall' => array(
      'arguments' => array('form' => NULL),
91
      'file' => 'system.admin.inc',
92
93
94
    ),
    'status_report' => array(
      'arguments' => array('requirements' => NULL),
95
      'file' => 'system.admin.inc',
96
97
98
    ),
    'admin_page' => array(
      'arguments' => array('blocks' => NULL),
99
      'file' => 'system.admin.inc',
100
101
102
    ),
    'admin_block' => array(
      'arguments' => array('block' => NULL),
103
      'file' => 'system.admin.inc',
104
105
106
    ),
    'admin_block_content' => array(
      'arguments' => array('content' => NULL),
107
      'file' => 'system.admin.inc',
108
109
110
    ),
    'system_admin_by_module' => array(
      'arguments' => array('menu_items' => NULL),
111
      'file' => 'system.admin.inc',
112
    ),
113
114
115
    'system_powered_by' => array(
      'arguments' => array('image_path' => NULL),
    ),
116
117
  ));
}
Dries's avatar
   
Dries committed
118
119
120
/**
 * Implementation of hook_perm().
 */
Dries's avatar
 
Dries committed
121
function system_perm() {
122
  return array('administer site configuration', 'access administration pages', 'administer actions', 'select different theme', 'administer files');
Dries's avatar
   
Dries committed
123
124
}

125
126
127
128
129
/**
 * Implementation of hook_elements().
 */
function system_elements() {
  // Top level form
130
  $type['form'] = array('#method' => 'post', '#action' => request_uri());
131
132

  // Inputs
133
134
135
136
137
  $type['submit'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => TRUE, '#process' => array('form_expand_ahah'));
  $type['button'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => FALSE, '#process' => array('form_expand_ahah'));
  $type['image_button'] = array('#input' => TRUE, '#button_type' => 'submit','#executes_submit_callback' => TRUE, '#process' => array('form_expand_ahah'), '#return_value' => TRUE, '#has_garbage_value' => TRUE, '#src' => NULL);
  $type['textfield'] = array('#input' => TRUE, '#size' => 60, '#maxlength' => 128, '#autocomplete_path' => FALSE, '#process' => array('form_expand_ahah'));
  $type['password'] = array('#input' => TRUE, '#size' => 60, '#maxlength' => 128, '#process' => array('form_expand_ahah'));
138
  $type['password_confirm'] = array('#input' => TRUE, '#process' => array('expand_password_confirm'));
139
  $type['textarea'] = array('#input' => TRUE, '#cols' => 60, '#rows' => 5, '#resizable' => TRUE, '#process' => array('form_expand_ahah'));
140
  $type['radios'] = array('#input' => TRUE, '#process' => array('expand_radios'));
141
  $type['radio'] = array('#input' => TRUE, '#default_value' => NULL, '#process' => array('form_expand_ahah'));
142
  $type['checkboxes'] = array('#input' => TRUE, '#process' => array('expand_checkboxes'), '#tree' => TRUE);
143
144
145
  $type['checkbox'] = array('#input' => TRUE, '#return_value' => 1, '#process' => array('form_expand_ahah'));
  $type['select'] = array('#input' => TRUE, '#size' => 0, '#multiple' => FALSE, '#process' => array('form_expand_ahah'));
  $type['weight'] = array('#input' => TRUE, '#delta' => 10, '#default_value' => 0, '#process' => array('process_weight', 'form_expand_ahah'));
146
  $type['date'] = array('#input' => TRUE, '#process' => array('expand_date'), '#element_validate' => array('date_validate'));
147
  $type['file'] = array('#input' => TRUE, '#size' => 60);
148
149

  // Form structure
150
  $type['item'] = array('#value' => '');
151
  $type['hidden'] = array('#input' => TRUE, '#process' => array('form_expand_ahah'));
152
153
  $type['value'] = array('#input' => TRUE);
  $type['markup'] = array('#prefix' => '', '#suffix' => '');
154
  $type['fieldset'] = array('#collapsible' => FALSE, '#collapsed' => FALSE, '#value' => NULL, '#process' => array('form_expand_ahah'));
Dries's avatar
Dries committed
155
  $type['token'] = array('#input' => TRUE);
156
157
158
  return $type;
}

Dries's avatar
   
Dries committed
159
/**
Dries's avatar
   
Dries committed
160
 * Implementation of hook_menu().
Dries's avatar
   
Dries committed
161
 */
162
163
function system_menu() {
  $items['system/files'] = array(
164
    'title' => 'File download',
165
166
167
168
169
    'page callback' => 'file_download',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  $items['admin'] = array(
170
    'title' => 'Administer',
171
172
173
    'access arguments' => array('access administration pages'),
    'page callback' => 'system_main_admin_page',
    'weight' => 9,
174
    'file' => 'system.admin.inc',
175
176
  );
  $items['admin/compact'] = array(
177
    'title' => 'Compact mode',
178
179
    'page callback' => 'system_admin_compact_page',
    'type' => MENU_CALLBACK,
180
    'file' => 'system.admin.inc',
181
182
  );
  $items['admin/by-task'] = array(
183
    'title' => 'By task',
184
    'page callback' => 'system_main_admin_page',
185
    'file' => 'system.admin.inc',
186
187
188
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/by-module'] = array(
189
    'title' => 'By module',
190
    'page callback' => 'system_admin_by_module',
191
    'file' => 'system.admin.inc',
192
193
194
    'type' => MENU_LOCAL_TASK,
    'weight' => 2,
  );
195
196
197
198
199
200
201
202
203
204
  $items['admin/content'] = array(
    'title' => 'Content management',
    'description' => "Manage your site's content.",
    'position' => 'left',
    'weight' => -10,
    'page callback' => 'system_admin_menu_block_page',
    'access arguments' => array('access administration pages'),
    'file' => 'system.admin.inc',
  );

205
206
  // menu items that are basically just menu blocks
  $items['admin/settings'] = array(
207
208
    'title' => 'Site configuration',
    'description' => 'Adjust basic site configuration options.',
209
210
211
212
    'position' => 'right',
    'weight' => -5,
    'page callback' => 'system_settings_overview',
    'access arguments' => array('administer site configuration'),
213
    'file' => 'system.admin.inc',
214
215
  );
  $items['admin/build'] = array(
216
217
    'title' => 'Site building',
    'description' => 'Control how your site looks and feels.',
218
219
220
221
    'position' => 'right',
    'weight' => -10,
    'page callback' => 'system_admin_menu_block_page',
    'access arguments' => array('administer site configuration'),
222
    'file' => 'system.admin.inc',
223
224
  );
  $items['admin/settings/admin'] = array(
225
226
    'title' => 'Administration theme',
    'description' => 'Settings for how your administrative pages should look.',
227
228
229
230
    'position' => 'left',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_admin_theme_settings'),
    'block callback' => 'system_admin_theme_settings',
231
    'file' => 'system.admin.inc',
232
233
234
  );
  // Themes:
  $items['admin/build/themes'] = array(
235
236
    'title' => 'Themes',
    'description' => 'Change which theme your site uses or allows users to set.',
237
    'page callback' => 'drupal_get_form',
238
    'page arguments' => array('system_themes_form', NULL),
239
    'file' => 'system.admin.inc',
240
241
  );
  $items['admin/build/themes/select'] = array(
242
243
    'title' => 'List',
    'description' => 'Select the default theme.',
244
245
246
247
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -1,
  );
  $items['admin/build/themes/settings'] = array(
248
    'title' => 'Configure',
249
    'page arguments' => array('system_theme_settings'),
250
251
252
253
    'type' => MENU_LOCAL_TASK,
  );
  // Theme configuration subtabs
  $items['admin/build/themes/settings/global'] = array(
254
    'title' => 'Global settings',
255
256
257
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -1,
  );
Dries's avatar
   
Dries committed
258

259
260
261
  foreach (list_themes() as $theme) {
    if ($theme->status) {
      $items['admin/build/themes/settings/'. $theme->name] = array(
262
        'title' => $theme->info['name'],
263
264
265
        'page arguments' => array('system_theme_settings', $theme->name),
        'type' => MENU_LOCAL_TASK,
      );
Dries's avatar
   
Dries committed
266
    }
Dries's avatar
   
Dries committed
267
  }
drumm's avatar
drumm committed
268

269
270
  // Modules:
  $items['admin/build/modules'] = array(
271
272
    'title' => 'Modules',
    'description' => 'Enable or disable add-on modules for your site.',
273
274
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_modules'),
275
    'file' => 'system.admin.inc',
276
277
  );
  $items['admin/build/modules/list'] = array(
278
    'title' => 'List',
279
280
281
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/build/modules/list/confirm'] = array(
282
    'title' => 'List',
283
284
285
    'type' => MENU_CALLBACK,
  );
  $items['admin/build/modules/uninstall'] = array(
286
    'title' => 'Uninstall',
287
288
289
290
    'page arguments' => array('system_modules_uninstall'),
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/build/modules/uninstall/confirm'] = array(
291
    'title' => 'Uninstall',
292
293
    'type' => MENU_CALLBACK,
  );
Dries's avatar
   
Dries committed
294

295
  // Actions:
296
  $items['admin/settings/actions'] = array(
297
298
299
300
301
    'title' => 'Actions',
    'description' => 'Manage the actions defined for your site.',
    'access arguments' => array('administer actions'),
    'page callback' => 'system_actions_manage'
  );
302
  $items['admin/settings/actions/manage'] = array(
303
304
305
306
307
308
    'title' => 'Manage actions',
    'description' => 'Manage the actions defined for your site.',
    'page callback' => 'system_actions_manage',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -2,
  );
309
310
  $items['admin/settings/actions/configure'] = array(
    'title' => 'Configure an advanced action',
311
312
313
314
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_actions_configure'),
    'type' => MENU_CALLBACK,
  );
315
  $items['admin/settings/actions/delete/%actions'] = array(
316
317
318
319
320
321
    'title' => 'Delete action',
    'description' => 'Delete an action.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_actions_delete_form', 4),
    'type' => MENU_CALLBACK,
  );
322
  $items['admin/settings/actions/orphan'] = array(
323
324
325
326
327
    'title' => 'Remove orphans',
    'page callback' => 'system_actions_remove_orphans',
    'type' => MENU_CALLBACK,
  );

328
329
  // Settings:
  $items['admin/settings/site-information'] = array(
330
331
    'title' => 'Site information',
    'description' => 'Change basic site information, such as the site name, slogan, e-mail address, mission, front page and more.',
332
333
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_site_information_settings'),
334
    'file' => 'system.admin.inc',
335
336
  );
  $items['admin/settings/error-reporting'] = array(
337
338
    'title' => 'Error reporting',
    'description' => 'Control how Drupal deals with errors including 403/404 errors as well as PHP error reporting.',
339
340
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_error_reporting_settings'),
341
    'file' => 'system.admin.inc',
342
  );
343
  $items['admin/settings/logging'] = array(
344
345
    'title' => 'Logging and alerts',
    'description' => "Settings for logging and alerts modules. Various modules can route Drupal's system events to different destination, such as syslog, database, email, ...etc.",
346
    'page callback' => 'system_logging_overview',
347
    'file' => 'system.admin.inc',
348
  );
349
  $items['admin/settings/performance'] = array(
350
    'title' => 'Performance',
351
    'description' => 'Enable or disable page caching for anonymous users and set CSS and JS bandwidth optimization options.',
352
353
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_performance_settings'),
354
    'file' => 'system.admin.inc',
355
356
  );
  $items['admin/settings/file-system'] = array(
357
358
    'title' => 'File system',
    'description' => 'Tell Drupal where to store uploaded files and how they are accessed.',
359
360
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_file_system_settings'),
361
    'file' => 'system.admin.inc',
362
363
  );
  $items['admin/settings/image-toolkit'] = array(
364
365
    'title' => 'Image toolkit',
    'description' => 'Choose which image toolkit to use if you have installed optional toolkits.',
366
367
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_image_toolkit_settings'),
368
    'file' => 'system.admin.inc',
369
370
  );
  $items['admin/content/rss-publishing'] = array(
371
372
    'title' => 'RSS publishing',
    'description' => 'Configure the number of items per feed and whether feeds should be titles/teasers/full-text.',
373
374
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_rss_feeds_settings'),
375
    'access arguments' => array('administer site configuration'),
376
    'file' => 'system.admin.inc',
377
378
  );
  $items['admin/settings/date-time'] = array(
379
380
    'title' => 'Date and time',
    'description' => "Settings for how Drupal displays date and time, as well as the system's default timezone.",
381
382
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_date_time_settings'),
383
    'file' => 'system.admin.inc',
384
  );
385
386
387
388
  $items['admin/settings/date-time/lookup'] = array(
    'title' => t('Date and time lookup'),
    'type' => MENU_CALLBACK,
    'page callback' => 'system_date_time_lookup',
389
    'file' => 'system.admin.inc',
390
  );
391
  $items['admin/settings/site-maintenance'] = array(
392
393
    'title' => 'Site maintenance',
    'description' => 'Take the site off-line for maintenance or bring it back online.',
394
395
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_site_maintenance_settings'),
396
    'file' => 'system.admin.inc',
397
398
  );
  $items['admin/settings/clean-urls'] = array(
399
400
    'title' => 'Clean URLs',
    'description' => 'Enable or disable clean URLs for your site.',
401
402
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_clean_url_settings'),
403
    'file' => 'system.admin.inc',
404
  );
405
406
407
408
409
410
411
  $items['admin/settings/clean-urls/check'] = array(
    'title' => 'Clean URL check',
    'page callback' => 'drupal_json',
    'page arguments' => array(array('status' => TRUE)),
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
412

413
414
415
416
  // Reports:
  $items['admin/reports'] = array(
    'title' => 'Reports',
    'description' => 'View reports from system logs and other status information.',
417
418
419
    'page callback' => 'system_admin_menu_block_page',
    'weight' => 5,
    'position' => 'left',
420
    'file' => 'system.admin.inc',
421
  );
422
  $items['admin/reports/status'] = array(
423
424
    'title' => 'Status report',
    'description' => "Get a status report about your site's operation and any detected problems.",
425
426
427
    'page callback' => 'system_status',
    'weight' => 10,
    'access arguments' => array('administer site configuration'),
428
    'file' => 'system.admin.inc',
429
  );
430
  $items['admin/reports/status/run-cron'] = array(
431
    'title' => 'Run cron',
432
433
    'page callback' => 'system_run_cron',
    'type' => MENU_CALLBACK,
434
    'file' => 'system.admin.inc',
435
  );
436
  $items['admin/reports/status/php'] = array(
437
    'title' => 'PHP',
438
439
    'page callback' => 'system_php',
    'type' => MENU_CALLBACK,
440
    'file' => 'system.admin.inc',
441
  );
442
  $items['admin/reports/status/sql'] = array(
443
    'title' => 'SQL',
444
445
    'page callback' => 'system_sql',
    'type' => MENU_CALLBACK,
446
    'file' => 'system.admin.inc',
447
  );
448
449
450
451
452
  // Default page for batch operations
  $items['batch'] = array(
    'page callback' => 'system_batch_page',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
453
    'file' => 'system.admin.inc',
454
  );
Dries's avatar
   
Dries committed
455
  return $items;
Dries's avatar
 
Dries committed
456
457
}

458
459
function system_init() {
  // Use the administrative theme if the user is looking at a page in the admin/* path.
460
  if (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit'))) {
461
462
463
464
465
466
467
468
    global $custom_theme;
    $custom_theme = variable_get('admin_theme', '0');
    drupal_add_css(drupal_get_path('module', 'system') .'/admin.css', 'module');
  }

  // Add the CSS for this module.
  drupal_add_css(drupal_get_path('module', 'system') .'/defaults.css', 'module');
  drupal_add_css(drupal_get_path('module', 'system') .'/system.css', 'module');
469
  drupal_add_css(drupal_get_path('module', 'system') .'/system-menus.css', 'module');
470
471
}

Dries's avatar
   
Dries committed
472
473
474
475
476
/**
 * Implementation of hook_user().
 *
 * Allows users to individually set their theme and time zone.
 */
477
function system_user($type, $edit, &$user, $category = NULL) {
Dries's avatar
Dries committed
478
  if ($type == 'form' && $category == 'account') {
479
    $form['theme_select'] = system_theme_select_form(t('Selecting a different theme will change the look and feel of the site.'), isset($edit['theme']) ? $edit['theme'] : NULL, 2);
Dries's avatar
Dries committed
480

481
    if (variable_get('configurable_timezones', 1)) {
Steven Wittens's avatar
Steven Wittens committed
482
      $zones = _system_zonelist();
483
      $form['timezone'] = array(
484
        '#type' => 'fieldset',
485
486
487
488
        '#title' => t('Locale settings'),
        '#weight' => 6,
        '#collapsible' => TRUE,
      );
489
      $form['timezone']['timezone'] = array(
490
491
492
493
494
        '#type' => 'select',
        '#title' => t('Time zone'),
        '#default_value' => strlen($edit['timezone']) ? $edit['timezone'] : variable_get('date_default_timezone', 0),
        '#options' => $zones,
        '#description' => t('Select your current local time. Dates and times throughout this site will be displayed using this time zone.'),
495
      );
Dries's avatar
   
Dries committed
496
    }
Dries's avatar
Dries committed
497

498
    return $form;
Dries's avatar
   
Dries committed
499
  }
Dries's avatar
   
Dries committed
500
501
}

502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
/**
 * Generate a block with a promotional link to Drupal.org.
 */
function system_block($op = 'list', $delta = 0, $edit = NULL) {
  switch($op) {
    case 'list':
      $blocks[0] = array(
        'info' => t('Powered by Drupal'),
        'weight' => '10',
        'status' => 1,
        'region' => 'footer',
      );
      return $blocks;
    case 'configure':
      // Compile a list of fields to show
      $form['wrapper']['color'] = array(
        '#type' => 'select',
        '#title' => t('Badge color'),
        '#default_value' => variable_get('drupal_badge_color', 'powered-blue'),
        '#options' => array('powered-black' => t('Black'), 'powered-blue' => t('Blue'), 'powered-gray' => t('Gray')),
      );
      $form['wrapper']['size'] = array(
        '#type' => 'select',
        '#title' => t('Badge size'),
        '#default_value' => variable_get('drupal_badge_size', '80x15'),
        '#options' => array('80x15' => t('Small'), '88x31' => t('Medium'), '135x42' => t('Large')),
      );
      return $form;
    case 'save':
      variable_set('drupal_badge_color', $edit['color']);
      variable_set('drupal_badge_size', $edit['size']);
      break;
    case 'view':
      $image_path = 'misc/'. variable_get('drupal_badge_color', 'powered-blue') .'-'. variable_get('drupal_badge_size', '80x15') .'.png';
      $block['subject'] = NULL; // Don't display a title
      $block['content'] = theme('system_powered_by', $image_path);
      return $block;
  }
}

542
543
544
/**
 * Provide a single block on the administration overview page.
 */
545
function system_admin_menu_block($item) {
546
  $content = array();
547
  if (!isset($item['mlid'])) {
548
    $item += db_fetch_array(db_query("SELECT mlid, menu_name FROM {menu_links} ml WHERE ml.router_path = '%s' AND module = 'system'", $item['path']));
549
  }
550
  $result = db_query("
551
    SELECT m.*, ml.*
552
553
    FROM {menu_links} ml
    INNER JOIN {menu_router} m ON ml.router_path = m.path
554
    WHERE ml.plid = %d AND ml.menu_name = '%s' AND hidden = 0", $item['mlid'], $item['menu_name']);
555
  while ($item = db_fetch_array($result)) {
556
    _menu_link_translate($item);
557
    if (!$item['access']) {
558
      continue;
559
    }
560
561
562
563
564
565
566
567
    // The link 'description' either derived from the hook_menu 'description' or
    // entered by the user via menu module is saved as the title attribute.
    if (!empty($item['options']['attributes']['title'])) {
      $item['description'] = $item['options']['attributes']['title'];
    }
    // Prepare for sorting as in function _menu_tree_check_access().
    // The weight is offset so it is always positive, with a uniform 5-digits.
    $content[(50000 + $item['weight']) .' '. $item['title'] .' '. $item['mlid']] = $item;
568
  }
569
  ksort($content);
570
571
572
573
  return $content;
}


574
function system_admin_theme_submit($form, &$form_state) {
575
  // If we're changing themes, make sure the theme has its blocks initialized.
576
  if ($form_state['values']['admin_theme'] && $form_state['values']['admin_theme'] != variable_get('admin_theme', '0')) {
577
578
    $result = db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme = '%s'", $form_state['values']['admin_theme']));
    if (!$result) {
579
      system_initialize_theme_blocks($form_state['values']['admin_theme']);
580
581
582
583
    }
  }
}

584
/**
585
586
587
588
589
590
591
592
593
594
595
 * Returns a fieldset containing the theme select form.
 *
 * @param $description
 *    description of the fieldset
 * @param $default_value
 *    default value of theme radios
 * @param $weight
 *    weight of the fieldset
 * @return
 *    a form array
 */
596
function system_theme_select_form($description = '', $default_value = '', $weight = 0) {
597
  if (user_access('select different theme')) {
598
    $enabled = array();
599
600
601
    $themes = list_themes();

    foreach ($themes as $theme) {
602
603
604
605
606
607
608
609
610
      if ($theme->status) {
        $enabled[] = $theme;
      }
    }

    if (count($enabled) > 1) {
      ksort($enabled);

      $form['themes'] = array(
Dries's avatar
Dries committed
611
612
613
614
        '#type' => 'fieldset',
        '#title' => t('Theme configuration'),
        '#description' => $description,
        '#collapsible' => TRUE,
615
616
617
618
619
        '#theme' => 'system_theme_select_form'
      );

      foreach ($enabled as $info) {
        // For the default theme, revert to an empty string so the user's theme updates when the site theme is changed.
620
        $info->key = $info->name == variable_get('theme_default', 'garland') ? '' : $info->name;
621

622
623
624
625
626
627
628
629
630
631
632
        $screenshot = NULL;
        $theme_key = $info->name;
        while ($theme_key) {
          if (file_exists($themes[$theme_key]->info['screenshot'])) {
            $screenshot = $themes[$theme_key]->info['screenshot'];
            break;
          }
          $theme_key = isset($themes[$theme_key]->info['base theme']) ? $themes[$theme_key]->info['base theme'] : NULL;
        }

        $screenshot = $screenshot ? theme('image', $screenshot, t('Screenshot for %theme theme', array('%theme' => $info->name)), '', array('class' => 'screenshot'), FALSE) : t('no screenshot');
633

634
        $form['themes'][$info->key]['screenshot'] = array('#value' => $screenshot);
635
        $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>' : ''));
636
637
638
639
640
641
642
643
644
645
        $options[$info->key] = '';
      }

      $form['themes']['theme'] = array('#type' => 'radios', '#options' => $options, '#default_value' => $default_value ? $default_value : '');
      $form['#weight'] = $weight;
      return $form;
    }
  }
}

646
647
/**
 * Checks the existence of the directory specified in $form_element. This
Dries's avatar
Dries committed
648
 * function is called from the system_settings form to check both the
649
650
651
652
653
654
655
 * file_directory_path and file_directory_temp directories. If validation
 * fails, the form element is flagged with an error from within the
 * file_check_directory function.
 *
 * @param $form_element
 *   The form element containing the name of the directory to check.
 */
656
function system_check_directory($form_element) {
657
658
659
660
  file_check_directory($form_element['#value'], FILE_CREATE_DIRECTORY, $form_element['#parents'][0]);
  return $form_element;
}

Dries's avatar
   
Dries committed
661
662
663
664
/**
 * Retrieves the current status of an array of files in the system table.
 */
function system_get_files_database(&$files, $type) {
Dries's avatar
   
Dries committed
665
  // Extract current files from database.
666
  $result = db_query("SELECT filename, name, type, status, throttle, schema_version FROM {system} WHERE type = '%s'", $type);
Dries's avatar
   
Dries committed
667
  while ($file = db_fetch_object($result)) {
668
    if (isset($files[$file->name]) && is_object($files[$file->name])) {
669
      $file->old_filename = $file->filename;
Dries's avatar
   
Dries committed
670
      foreach ($file as $key => $value) {
671
        if (!isset($files[$file->name]) || !isset($files[$file->name]->$key)) {
Dries's avatar
Dries committed
672
673
          $files[$file->name]->$key = $value;
        }
Dries's avatar
   
Dries committed
674
      }
675
    }
Dries's avatar
 
Dries committed
676
  }
Dries's avatar
   
Dries committed
677
}
Dries's avatar
 
Dries committed
678

679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
function system_theme_default() {
  // Prepare defaults for themes.
  return array(
    'regions' => array(
      'left' => 'Left sidebar',
      'right' => 'Right sidebar',
      'content' => 'Content',
      'header' => 'Header',
      'footer' => 'Footer',
    ),
    'description' => '',
    'features' => array(
      'comment_user_picture',
      'favicon',
      'mission',
      'logo',
      'name',
      'node_user_picture',
      'search',
698
699
700
      'slogan',
      'primary_links',
      'secondary_links',
701
    ),
702
703
704
705
    'stylesheets' => array(
      'all' => array('style.css')
    ),
    'scripts' => array('script.js'),
706
    'screenshot' => 'screenshot.png',
707
    'php' => DRUPAL_MINIMUM_PHP,
708
709
710
  );
}

Dries's avatar
   
Dries committed
711
712
713
/**
 * Collect data about all currently available themes
 */
Dries's avatar
Dries committed
714
715
function system_theme_data() {
  // Find themes
716
  $themes = drupal_system_listing('\.info$', 'themes');
Dries's avatar
Dries committed
717

Dries's avatar
   
Dries committed
718
  // Find theme engines
719
  $engines = drupal_system_listing('\.engine$', 'themes/engines');
Dries's avatar
Dries committed
720
721

  // Remove all theme engines from the system table
722
  db_query("DELETE FROM {system} WHERE type = '%s'", 'theme_engine');
Dries's avatar
   
Dries committed
723
724

  foreach ($engines as $engine) {
Dries's avatar
   
Dries committed
725
    // Insert theme engine into system table
Dries's avatar
Dries committed
726
727
728
    drupal_get_filename('theme_engine', $engine->name, $engine->filename);
    drupal_load('theme_engine', $engine->name);
    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);
729
  }
Dries's avatar
Dries committed
730

731
  $defaults = system_theme_default();
732

733
734
735
736
  $sub_themes = array();
  // Read info files for each theme
  foreach ($themes as $key => $theme) {
    $themes[$key]->info = drupal_parse_info_file($theme->filename) + $defaults;
737
738
739
740
741

    // Invoke hook_system_info_alter() to give installed modules a chance to
    // modify the data in the .info files if necessary.
    drupal_alter('system_info', $themes[$key]->info, $themes[$key]);

742
743
744
745
746
747
748
749
    if (!empty($themes[$key]->info['base theme'])) {
      $sub_themes[] = $key;
    }
    if (empty($themes[$key]->info['engine'])) {
      $filename = dirname($themes[$key]->filename) .'/'. $themes[$key]->name .'.theme';
      if (file_exists($filename)) {
        $themes[$key]->owner = $filename;
        $themes[$key]->prefix = $key;
Dries's avatar
   
Dries committed
750
      }
Dries's avatar
   
Dries committed
751
    }
752
753
754
755
756
757
758
759
760
    else {
      $engine = $themes[$key]->info['engine'];
      if (isset($engines[$engine])) {
        $themes[$key]->owner = $engines[$engine]->filename;
        $themes[$key]->prefix = $engines[$engine]->name;
        $themes[$key]->template = TRUE;
      }
    }

761
762
763
764
765
766
    // Give the stylesheets proper path information.
    $pathed_stylesheets = array();
    foreach ($themes[$key]->info['stylesheets'] as $media => $stylesheets) {
      foreach ($stylesheets as $stylesheet) {
        $pathed_stylesheets[$media][$stylesheet] = dirname($themes[$key]->filename) .'/'. $stylesheet;
      }
767
    }
768
    $themes[$key]->info['stylesheets'] = $pathed_stylesheets;
Dries's avatar
Dries committed
769

770
771
772
773
    // Give the scripts proper path information.
    $scripts = array();
    foreach ($themes[$key]->info['scripts'] as $script) {
      $scripts[$script] = dirname($themes[$key]->filename) .'/'. $script;
774
    }
775
    $themes[$key]->info['scripts'] = $scripts;
776
777
778
779
    // Give the screenshot proper path information.
    if (!empty($themes[$key]->info['screenshot'])) {
      $themes[$key]->info['screenshot'] = dirname($themes[$key]->filename) .'/'. $themes[$key]->info['screenshot'];
    }
Dries's avatar
   
Dries committed
780
781
  }

782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
  // Now that we've established all our master themes, go back and fill in
  // data for subthemes.
  foreach ($sub_themes as $key) {
    $base_key = system_find_base_theme($themes, $key);
    if (!$base_key) {
      continue;
    }
    // Copy the 'owner' and 'engine' over if the top level theme uses a
    // theme engine.
    if (isset($themes[$base_key]->owner)) {
      if (isset($themes[$base_key]->info['engine'])) {
        $themes[$key]->info['engine'] = $themes[$base_key]->info['engine'];
        $themes[$key]->owner = $themes[$base_key]->owner;
        $themes[$key]->prefix = $themes[$base_key]->prefix;
      }
      else {
        $themes[$key]->prefix = $key;
Dries's avatar
   
Dries committed
799
800
      }
    }
Dries's avatar
   
Dries committed
801
  }
Dries's avatar
   
Dries committed
802
803

  // Extract current files from database.
Dries's avatar
Dries committed
804
805
806
  system_get_files_database($themes, 'theme');

  db_query("DELETE FROM {system} WHERE type = 'theme'");
Dries's avatar
   
Dries committed
807

Dries's avatar
Dries committed
808
  foreach ($themes as $theme) {
809
810
811
812
    if (!isset($theme->owner)) {
      $theme->owner = '';
    }

813
    db_query("INSERT INTO {system} (name, owner, info, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d, %d)", $theme->name, $theme->owner, serialize($theme->info), 'theme', $theme->filename, isset($theme->status) ? $theme->status : 0, 0, 0);
Dries's avatar
Dries committed
814
815
816
817
818
  }

  return $themes;
}

819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
/**
 * Recursive function to find the top level base theme. Themes can inherit
 * templates and function implementations from earlier themes; this function
 * finds the top level parent that has no ancestor, or returns NULL if there
 * isn't a valid parent.
 */
function system_find_base_theme($themes, $key, $used_keys = array()) {
  $base_key = $themes[$key]->info['base theme'];
  // Does the base theme exist?
  if (!isset($themes[$base_key])) {
    return NULL;
  }

  // Is the base theme itself a child of another theme?
  if (isset($themes[$base_key]->info['base theme'])) {
    // Prevent loops.
835
    if (!empty($used_keys[$base_key])) {
836
837
838
839
840
841
842
843
844
      return NULL;
    }
    $used_keys[$base_key] = TRUE;
    return system_find_base_theme($themes, $base_key, $used_keys);
  }
  // If we get here, then this is our parent theme.
  return $base_key;
}

845
846
847
/**
 * Get a list of available regions from a specified theme.
 *
848
 * @param $theme_key
849
850
851
852
 *   The name of a theme.
 * @return
 *   An array of regions in the form $region['name'] = 'description'.
 */
853
function system_region_list($theme_key) {
854
855
  static $list = array();

856
  if (!array_key_exists($theme_key, $list)) {
857
858
    $info = unserialize(db_result(db_query("SELECT info FROM {system} WHERE type = 'theme' AND name = '%s'", $theme_key)));
    $list[$theme_key] = array_map('t', $info['regions']);
859
860
  }

861
  return $list[$theme_key];
862
863
864
865
866
867
868
869
870
871
872
873
}

/**
 * Get the name of the default region for a given theme.
 *
 * @param $theme
 *   The name of a theme.
 * @return
 *   A string that is the region name.
 */
function system_default_region($theme) {
  $regions = array_keys(system_region_list($theme));
874
  return isset($regions[0]) ? $regions[0] : '';
875
876
}

Dries's avatar
   
Dries committed
877
/**
878
879
 * Assign an initial, default set of blocks for a theme.
 *
880
 * This function is called the first time a new theme is enabled. The new theme
881
882
883
884
885
886
887
888
889
 * gets a copy of the default theme's blocks, with the difference that if a
 * particular region isn't available in the new theme, the block is assigned
 * to the new theme's default region.
 *
 * @param $theme
 *   The name of a theme.
 */
function system_initialize_theme_blocks($theme) {
  // Initialize theme's blocks if none already registered.
890
  if (!(db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme = '%s'", $theme)))) {
891
    $default_theme = variable_get('theme_default', 'garland');
892
893
    $regions = system_region_list($theme);
    $result = db_query("SELECT * FROM {blocks} WHERE theme = '%s'", $default_theme);
894
    while ($block = db_fetch_array($result)) {
895
896
897
898
      // If the region isn't supported by the theme, assign the block to the theme's default region.
      if (!array_key_exists($block['region'], $regions)) {
        $block['region'] = system_default_region($theme);
      }
899
900
      db_query("INSERT INTO {blocks} (module, delta, theme, status, weight, region, visibility, pages, custom, throttle, cache) VALUES ('%s', '%s', '%s', %d, %d, '%s', %d, '%s', %d, %d, %d)",
          $block['module'], $block['delta'], $theme, $block['status'], $block['weight'], $block['region'], $block['visibility'], $block['pages'], $block['custom'], $block['throttle'], $block['cache']);
901
902
903
904
    }
  }
}

905
906
907
908
/**
 * Add default buttons to a form and set its prefix
 */
function system_settings_form($form) {
909
910
  $form['buttons']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration') );
  $form['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset to defaults') );
911

912
  if (!empty($_POST) && form_get_errors()) {
913
    drupal_set_message(t('The settings have not been saved because of the errors.'), 'error');
914
  }
915
916
  $form['#submit'][] = 'system_settings_form_submit';
  $form['#validate'][] = 'system_settings_form_validate';
917
  $form['#theme'] = 'system_settings_form';
918
  return $form;
919
920
}

921

Steven Wittens's avatar
Steven Wittens committed
922

923
924
925
/**
 * Execute the system_settings_form.
 *
926
927
928
 * If you want node type configure style handling of your checkboxes,
 * add an array_filter value to your form.
 *
929
 */
930
931
function system_settings_form_submit($form, &$form_state) {
  $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
932

933
  // Exclude unnecessary elements.
934
  unset($form_state['values']['submit'], $form_state['values']['reset'], $form_state['values']['form_id'], $form_state['values']['op'], $form_state['values']['form_token'], $form_state['values']['form_build_id']);
935

936
  foreach ($form_state['values'] as $key