system.module 64.4 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, behaviours 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
60
61
62
63
64
65
    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>';
      }
66
      return $output;
67
68
    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").');
69
    case 'admin/logs/status':
70
      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>';
71
  }
Dries's avatar
   
Dries committed
72
73
}

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

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

  // Inputs
132
133
134
135
136
  $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'));
137
  $type['password_confirm'] = array('#input' => TRUE, '#process' => array('expand_password_confirm'));
138
  $type['textarea'] = array('#input' => TRUE, '#cols' => 60, '#rows' => 5, '#resizable' => TRUE, '#process' => array('form_expand_ahah'));
139
  $type['radios'] = array('#input' => TRUE, '#process' => array('expand_radios'));
140
  $type['radio'] = array('#input' => TRUE, '#default_value' => NULL, '#process' => array('form_expand_ahah'));
141
  $type['checkboxes'] = array('#input' => TRUE, '#process' => array('expand_checkboxes'), '#tree' => TRUE);
142
143
144
  $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'));
145
  $type['date'] = array('#input' => TRUE, '#process' => array('expand_date'), '#element_validate' => array('date_validate'));
146
  $type['file'] = array('#input' => TRUE, '#size' => 60);
147
148

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

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

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

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

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

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

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

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

450
451
function system_init() {
  // Use the administrative theme if the user is looking at a page in the admin/* path.
452
  if (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit'))) {
453
454
455
456
457
458
459
460
    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');
461
  drupal_add_css(drupal_get_path('module', 'system') .'/system-menus.css', 'module');
462
463
}

Dries's avatar
   
Dries committed
464
465
466
467
468
/**
 * Implementation of hook_user().
 *
 * Allows users to individually set their theme and time zone.
 */
469
function system_user($type, $edit, &$user, $category = NULL) {
Dries's avatar
Dries committed
470
  if ($type == 'form' && $category == 'account') {
471
    $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
472

473
    if (variable_get('configurable_timezones', 1)) {
Steven Wittens's avatar
Steven Wittens committed
474
      $zones = _system_zonelist();
475
      $form['timezone'] = array(
476
        '#type' => 'fieldset',
477
478
479
480
        '#title' => t('Locale settings'),
        '#weight' => 6,
        '#collapsible' => TRUE,
      );
481
      $form['timezone']['timezone'] = array(
482
483
484
485
486
        '#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.'),
487
      );
Dries's avatar
   
Dries committed
488
    }
Dries's avatar
Dries committed
489

490
    return $form;
Dries's avatar
   
Dries committed
491
  }
Dries's avatar
   
Dries committed
492
493
}

494
495
496
497
498
499
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
/**
 * 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;
  }
}

534
535
536
/**
 * Provide a single block on the administration overview page.
 */
537
function system_admin_menu_block($item) {
538
  $content = array();
539
  if (!isset($item['mlid'])) {
540
    $item += db_fetch_array(db_query("SELECT mlid, menu_name FROM {menu_links} ml WHERE ml.router_path = '%s' AND module = 'system'", $item['path']));
541
  }
542
  $result = db_query("
543
    SELECT m.*, ml.*
544
545
    FROM {menu_links} ml
    INNER JOIN {menu_router} m ON ml.router_path = m.path
546
    WHERE ml.plid = %d AND ml.menu_name = '%s' AND hidden = 0", $item['mlid'], $item['menu_name']);
547
  while ($item = db_fetch_array($result)) {
548
    _menu_link_translate($item);
549
    if (!$item['access']) {
550
      continue;
551
    }
552
553
554
555
556
557
558
559
    // 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;
560
  }
561
  ksort($content);
562
563
564
565
  return $content;
}


566
function system_admin_theme_submit($form, &$form_state) {
567
  // If we're changing themes, make sure the theme has its blocks initialized.
568
  if ($form_state['values']['admin_theme'] && $form_state['values']['admin_theme'] != variable_get('admin_theme', '0')) {
569
570
    $result = db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme = '%s'", $form_state['values']['admin_theme']));
    if (!$result) {
571
      system_initialize_theme_blocks($form_state['values']['admin_theme']);
572
573
574
575
    }
  }
}

576
/**
577
578
579
580
581
582
583
584
585
586
587
 * 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
 */
588
function system_theme_select_form($description = '', $default_value = '', $weight = 0) {
589
  if (user_access('select different theme')) {
590
    $enabled = array();
591
592
593
    $themes = list_themes();

    foreach ($themes as $theme) {
594
595
596
597
598
599
600
601
602
      if ($theme->status) {
        $enabled[] = $theme;
      }
    }

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

      $form['themes'] = array(
Dries's avatar
Dries committed
603
604
605
606
        '#type' => 'fieldset',
        '#title' => t('Theme configuration'),
        '#description' => $description,
        '#collapsible' => TRUE,
607
608
609
610
611
        '#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.
612
        $info->key = $info->name == variable_get('theme_default', 'garland') ? '' : $info->name;
613

614
615
616
617
618
619
620
621
622
623
624
        $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');
625

626
        $form['themes'][$info->key]['screenshot'] = array('#value' => $screenshot);
627
        $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>' : ''));
628
629
630
631
632
633
634
635
636
637
        $options[$info->key] = '';
      }

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

638
639
/**
 * Checks the existence of the directory specified in $form_element. This
Dries's avatar
Dries committed
640
 * function is called from the system_settings form to check both the
641
642
643
644
645
646
647
 * 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.
 */
648
function system_check_directory($form_element) {
649
650
651
652
  file_check_directory($form_element['#value'], FILE_CREATE_DIRECTORY, $form_element['#parents'][0]);
  return $form_element;
}

Dries's avatar
   
Dries committed
653
654
655
656
/**
 * 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
657
  // Extract current files from database.
658
  $result = db_query("SELECT filename, name, type, status, throttle, schema_version FROM {system} WHERE type = '%s'", $type);
Dries's avatar
   
Dries committed
659
  while ($file = db_fetch_object($result)) {
660
    if (isset($files[$file->name]) && is_object($files[$file->name])) {
661
      $file->old_filename = $file->filename;
Dries's avatar
   
Dries committed
662
      foreach ($file as $key => $value) {
663
        if (!isset($files[$file->name]) || !isset($files[$file->name]->$key)) {
Dries's avatar
Dries committed
664
665
          $files[$file->name]->$key = $value;
        }
Dries's avatar
   
Dries committed
666
      }
667
    }
Dries's avatar
 
Dries committed
668
  }
Dries's avatar
   
Dries committed
669
}
Dries's avatar
 
Dries committed
670

671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
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',
690
691
692
      'slogan',
      'primary_links',
      'secondary_links',
693
    ),
694
695
696
697
    'stylesheets' => array(
      'all' => array('style.css')
    ),
    'scripts' => array('script.js'),
698
    'screenshot' => 'screenshot.png',
699
    'php' => DRUPAL_MINIMUM_PHP,
700
701
702
  );
}

Dries's avatar
   
Dries committed
703
704
705
/**
 * Collect data about all currently available themes
 */
Dries's avatar
Dries committed
706
707
function system_theme_data() {
  // Find themes
708
  $themes = drupal_system_listing('\.info$', 'themes');
Dries's avatar
Dries committed
709

Dries's avatar
   
Dries committed
710
  // Find theme engines
711
  $engines = drupal_system_listing('\.engine$', 'themes/engines');
Dries's avatar
Dries committed
712
713

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

  foreach ($engines as $engine) {
Dries's avatar
   
Dries committed
717
    // Insert theme engine into system table
Dries's avatar
Dries committed
718
719
720
    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);
721
  }
Dries's avatar
Dries committed
722

723
  $defaults = system_theme_default();
724

725
726
727
728
  $sub_themes = array();
  // Read info files for each theme
  foreach ($themes as $key => $theme) {
    $themes[$key]->info = drupal_parse_info_file($theme->filename) + $defaults;
729
730
731
732
733

    // 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]);

734
735
736
737
738
739
740
741
    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
742
      }
Dries's avatar
   
Dries committed
743
    }
744
745
746
747
748
749
750
751
752
    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;
      }
    }

753
754
755
756
757
758
    // 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;
      }
759
    }
760
    $themes[$key]->info['stylesheets'] = $pathed_stylesheets;
Dries's avatar
Dries committed
761

762
763
764
765
    // Give the scripts proper path information.
    $scripts = array();
    foreach ($themes[$key]->info['scripts'] as $script) {
      $scripts[$script] = dirname($themes[$key]->filename) .'/'. $script;
766
    }
767
    $themes[$key]->info['scripts'] = $scripts;
768
769
770
771
    // 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
772
773
  }

774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
  // 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
791
792
      }
    }
Dries's avatar
   
Dries committed
793
  }
Dries's avatar
   
Dries committed
794
795

  // Extract current files from database.
Dries's avatar
Dries committed
796
797
798
  system_get_files_database($themes, 'theme');

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

Dries's avatar
Dries committed
800
  foreach ($themes as $theme) {
801
802
803
804
    if (!isset($theme->owner)) {
      $theme->owner = '';
    }

805
    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
806
807
808
809
810
  }

  return $themes;
}

811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
/**
 * 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.
827
    if (!empty($used_keys[$base_key])) {
828
829
830
831
832
833
834
835
836
      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;
}

837
838
839
/**
 * Get a list of available regions from a specified theme.
 *
840
 * @param $theme_key
841
842
843
844
 *   The name of a theme.
 * @return
 *   An array of regions in the form $region['name'] = 'description'.
 */
845
function system_region_list($theme_key) {
846
847
  static $list = array();

848
  if (!array_key_exists($theme_key, $list)) {
849
850
    $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']);
851
852
  }

853
  return $list[$theme_key];
854
855
856
857
858
859
860
861
862
863
864
865
}

/**
 * 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));
866
  return isset($regions[0]) ? $regions[0] : '';
867
868
}

Dries's avatar
   
Dries committed
869
/**
870
871
 * Assign an initial, default set of blocks for a theme.
 *
872
 * This function is called the first time a new theme is enabled. The new theme
873
874
875
876
877
878
879
880
881
 * 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.
882
  if (!(db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme = '%s'", $theme)))) {
883
    $default_theme = variable_get('theme_default', 'garland');
884
885
    $regions = system_region_list($theme);
    $result = db_query("SELECT * FROM {blocks} WHERE theme = '%s'", $default_theme);
886
    while ($block = db_fetch_array($result)) {
887
888
889
890
      // 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);
      }
891
892
      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']);
893
894
895
896
    }
  }
}

897
898
899
900
/**
 * Add default buttons to a form and set its prefix
 */
function system_settings_form($form) {
901
902
  $form['buttons']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration') );
  $form['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset to defaults') );
903

904
  if (!empty($_POST) && form_get_errors()) {
905
    drupal_set_message(t('The settings have not been saved because of the errors.'), 'error');
906
  }
907
908
  $form['#submit'][] = 'system_settings_form_submit';
  $form['#validate'][] = 'system_settings_form_validate';
909
  $form['#theme'] = 'system_settings_form';
910
  return $form;
911
912
}

913

Steven Wittens's avatar
Steven Wittens committed
914

915
916
917
/**
 * Execute the system_settings_form.
 *
918
919
920
 * If you want node type configure style handling of your checkboxes,
 * add an array_filter value to your form.
 *
921
 */
922
923
function system_settings_form_submit($form, &$form_state) {
  $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
924

925
  // Exclude unnecessary elements.
926
  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']);
927

928
  foreach ($form_state['values'] as $key => $value) {
929
930
931
932
    if ($op == t('Reset to defaults')) {
      variable_del($key);
    }
    else {
933
      if (is_array($value) && isset($form_state['values']['array_filter'])) {
934
935
936
937
938
939
940
        $value = array_keys(array_filter($value));
      }
      variable_set($key, $value);
    }
  }
  if ($op == t('Reset to defaults')) {
    drupal_set_message(t('The configuration options have been reset to their default values.'));
941
942
  }
  else {
943
944
    drupal_set_message(t('The configuration options have been saved.'));
  }