Code coverage for /20080809/includes/theme.inc

Line #Times calledCode
1
<?php
2
// $Id: theme.inc,v 1.431 2008/08/02 19:01:02 dries Exp $
3
4
/**
5
 * @file
6
 * The theme system, which controls the output of Drupal.
7
 *
8
 * The theme system allows for nearly all output of the Drupal system to
be
9
 * customized by user themes.
10
 *
11
 * @see <a href="http://drupal.org/node/253">Theme system</a>
12
 * @see themeable
13
 */
14
15
/**
16
 * @name Content markers
17
 * @{
18
 * Markers used by theme_mark() and node_mark() to designate content.
19
 * @see theme_mark(), node_mark()
20
 */
21
22
/**
23
 * Mark content as read.
24
 */
252027
define('MARK_READ', 0);
26
27
/**
28
 * Mark content as being new.
29
 */
302027
define('MARK_NEW', 1);
31
32
/**
33
 * Mark content as being updated.
34
 */
352027
define('MARK_UPDATED', 2);
36
37
/**
38
 * @} End of "Content markers".
39
 */
40
41
/**
42
 * Initialize the theme system by loading the theme.
43
 */
442027
function init_theme() {
452027
  global $theme, $user, $custom_theme, $theme_key;
46
47
  // If $theme is already set, assume the others are set, too, and do
nothing
482027
  if (isset($theme)) {
49830
    return;
500
  }
51
522027
  drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
532027
  $themes = list_themes();
54
55
  // Only select the user selected theme if it is available in the
56
  // list of enabled themes.
572027
  $theme = !empty($user->theme) && !empty($themes[$user->theme]->status) ?
$user->theme : variable_get('theme_default', 'garland');
58
59
  // Allow modules to override the present theme... only select custom
theme
60
  // if it is available in the list of installed themes.
612027
  $theme = $custom_theme && $themes[$custom_theme] ? $custom_theme :
$theme;
62
63
  // Store the identifier for retrieving theme settings with.
642027
  $theme_key = $theme;
65
66
  // Find all our ancestor themes and put them in an array.
672027
  $base_theme = array();
682027
  $ancestor = $theme;
692027
  while ($ancestor && isset($themes[$ancestor]->base_theme)) {
700
    $base_theme[] = $new_base_theme =
$themes[$themes[$ancestor]->base_theme];
710
    $ancestor = $themes[$ancestor]->base_theme;
720
  }
732027
  _init_theme($themes[$theme], array_reverse($base_theme));
742027
}
75
76
/**
77
 * Initialize the theme system given already loaded information. This
78
 * function is useful to initialize a theme when no database is present.
79
 *
80
 * @param $theme
81
 *   An object with the following information:
82
 *     filename
83
 *       The .info file for this theme. The 'path' to
84
 *       the theme will be in this file's directory. (Required)
85
 *     owner
86
 *       The path to the .theme file or the .engine file to load for
87
 *       the theme. (Required)
88
 *     stylesheet
89
 *       The primary stylesheet for the theme. (Optional)
90
 *     engine
91
 *       The name of theme engine to use. (Optional)
92
 * @param $base_theme
93
 *    An optional array of objects that represent the 'base theme' if the
94
 *    theme is meant to be derivative of another theme. It requires
95
 *    the same information as the $theme object. It should be in
96
 *    'oldest first' order, meaning the top level of the chain will
97
 *    be first.
98
 * @param $registry_callback
99
 *   The callback to invoke to set the theme registry.
100
 */
1012027
function _init_theme($theme, $base_theme = array(), $registry_callback =
'_theme_load_registry') {
1022027
  global $theme_info, $base_theme_info, $theme_engine, $theme_path;
1032027
  $theme_info = $theme;
1042027
  $base_theme_info = $base_theme;
105
1062027
  $theme_path = dirname($theme->filename);
107
108
  // Prepare stylesheets from this theme as well as all ancestor themes.
109
  // We work it this way so that we can have child themes override parent
110
  // theme stylesheets easily.
1112027
  $final_stylesheets = array();
112
113
  // Grab stylesheets from base theme
1142027
  foreach ($base_theme as $base) {
1150
    if (!empty($base->stylesheets)) {
1160
      foreach ($base->stylesheets as $media => $stylesheets) {
1170
        foreach ($stylesheets as $name => $stylesheet) {
1180
          $final_stylesheets[$media][$name] = $stylesheet;
1190
        }
1200
      }
1210
    }
1220
  }
123
124
  // Add stylesheets used by this theme.
1252027
  if (!empty($theme->stylesheets)) {
1262027
    foreach ($theme->stylesheets as $media => $stylesheets) {
1272027
      foreach ($stylesheets as $name => $stylesheet) {
1282027
        $final_stylesheets[$media][$name] = $stylesheet;
1292027
      }
1302027
    }
1312027
  }
132
133
  // And now add the stylesheets properly
1342027
  foreach ($final_stylesheets as $media => $stylesheets) {
1352027
    foreach ($stylesheets as $stylesheet) {
1362027
      drupal_add_css($stylesheet, 'theme', $media);
1372027
    }
1382027
  }
139
140
  // Do basically the same as the above for scripts
1412027
  $final_scripts = array();
142
143
  // Grab scripts from base theme
1442027
  foreach ($base_theme as $base) {
1450
    if (!empty($base->scripts)) {
1460
      foreach ($base->scripts as $name => $script) {
1470
        $final_scripts[$name] = $script;
1480
      }
1490
    }
1500
  }
151
152
  // Add scripts used by this theme.
1532027
  if (!empty($theme->scripts)) {
1540
    foreach ($theme->scripts as $name => $script) {
1550
      $final_scripts[$name] = $script;
1560
    }
1570
  }
158
159
  // Add scripts used by this theme.
1602027
  foreach ($final_scripts as $script) {
1610
    drupal_add_js($script, 'theme');
1620
  }
163
1642027
  $theme_engine = NULL;
165
166
  // Initialize the theme.
1672027
  if (isset($theme->engine)) {
168
    // Include the engine.
1692027
    include_once './' . $theme->owner;
170
1712027
    $theme_engine = $theme->engine;
1722027
    if (function_exists($theme_engine . '_init')) {
1732027
      foreach ($base_theme as $base) {
1740
        call_user_func($theme_engine . '_init', $base);
1750
      }
1762027
      call_user_func($theme_engine . '_init', $theme);
1772027
    }
1782027
  }
179
  else {
180
    // include non-engine theme files
1810
    foreach ($base_theme as $base) {
182
      // Include the theme file or the engine.
1830
      if (!empty($base->owner)) {
1840
        include_once './' . $base->owner;
1850
      }
1860
    }
187
    // and our theme gets one too.
1880
    if (!empty($theme->owner)) {
1890
      include_once './' . $theme->owner;
1900
    }
191
  }
192
1932027
  if (drupal_function_exists($registry_callback)) {
1942027
    $registry_callback($theme, $base_theme, $theme_engine);
1952027
  }
1962027
}
197
198
/**
199
 * Retrieve the stored theme registry. If the theme registry is already
200
 * in memory it will be returned; otherwise it will attempt to load the
201
 * registry from cache. If this fails, it will construct the registry and
202
 * cache it.
203
 */
2042027
function theme_get_registry($registry = NULL) {
2052027
  static $theme_registry = NULL;
2062027
  if (isset($registry)) {
2072027
    $theme_registry = $registry;
2082027
  }
209
2102027
  return $theme_registry;
2110
}
212
213
/**
214
 * Store the theme registry in memory.
215
 */
2162027
function _theme_set_registry($registry) {
217
  // Pass through for setting of static variable.
2182027
  return theme_get_registry($registry);
2190
}
220
221
/**
222
 * Get the theme_registry cache from the database; if it doesn't exist,
build
223
 * it.
224
 *
225
 * @param $theme
226
 *   The loaded $theme object.
227
 * @param $base_theme
228
 *   An array of loaded $theme objects representing the ancestor themes in
229
 *   oldest first order.
230
 * @param theme_engine
231
 *   The name of the theme engine.
232
 */
2332027
function _theme_load_registry($theme, $base_theme = NULL, $theme_engine =
NULL) {
234
  // Check the theme registry cache; if it exists, use it.
2352027
  $cache = cache_get("theme_registry:$theme->name", 'cache');
2362027
  if (isset($cache->data)) {
2371936
    $registry = $cache->data;
2381936
  }
239
  else {
240
    // If not, build one and cache it.
24191
    $registry = _theme_build_registry($theme, $base_theme, $theme_engine);
24291
    _theme_save_registry($theme, $registry);
243
  }
2442027
  _theme_set_registry($registry);
2452027
}
246
247
/**
248
 * Write the theme_registry cache into the database.
249
 */
2502027
function _theme_save_registry($theme, $registry) {
25191
  cache_set("theme_registry:$theme->name", $registry);
25291
}
253
254
/**
255
 * Force the system to rebuild the theme registry; this should be called
256
 * when modules are added to the system, or when a dynamic system needs
257
 * to add more theme hooks.
258
 */
2592027
function drupal_theme_rebuild() {
26019
  cache_clear_all('theme_registry', 'cache', TRUE);
26119
}
262
263
/**
264
 * Process a single invocation of the theme hook. $type will be one
265
 * of 'module', 'theme_engine' or 'theme' and it tells us some
266
 * important information.
267
 *
268
 * Because $cache is a reference, the cache will be continually
269
 * expanded upon; new entries will replace old entries in the
270
 * array_merge, but we are careful to ensure some data is carried
271
 * forward, such as the arguments a theme hook needs.
272
 *
273
 * An override flag can be set for preprocess functions. When detected the
274
 * cached preprocessors for the hook will not be merged with the newly
set.
275
 * This can be useful to themes and theme engines by giving them more
control
276
 * over how and when the preprocess functions are run.
277
 */
2782027
function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
27991
  $function = $name . '_theme';
28091
  if (function_exists($function)) {
28191
    $result = $function($cache, $type, $theme, $path);
282
28391
    foreach ($result as $hook => $info) {
28491
      $result[$hook]['type'] = $type;
28591
      $result[$hook]['theme path'] = $path;
286
      // if function and file are left out, default to standard naming
287
      // conventions.
28891
      if (!isset($info['template']) && !isset($info['function'])) {
28991
        $result[$hook]['function'] = ($type == 'module' ? 'theme_' : $name
. '_') . $hook;
29091
      }
291
      // If a path is set in the info, use what was set. Otherwise use the
292
      // default path. This is mostly so system.module can declare theme
293
      // functions on behalf of core .include files.
294
      // All files are included to be safe. Conditionally included
295
      // files can prevent them from getting registered.
29691
      if (isset($info['file']) && !isset($info['path'])) {
29791
        $result[$hook]['file'] = $path . '/' . $info['file'];
29891
        include_once($result[$hook]['file']);
29991
      }
30091
      elseif (isset($info['file']) && isset($info['path'])) {
3010
        include_once($info['path'] . '/' . $info['file']);
3020
      }
303
30491
      if (isset($info['template']) && !isset($info['path'])) {
30591
        $result[$hook]['template'] = $path . '/' . $info['template'];
30691
      }
307
      // If 'arguments' have been defined previously, carry them forward.
308
      // This should happen if a theme overrides a Drupal defined theme
309
      // function, for example.
31091
      if (!isset($info['arguments']) && isset($cache[$hook])) {
31191
        $result[$hook]['arguments'] = $cache[$hook]['arguments'];
31291
      }
313
      // Likewise with theme paths. These are used for template naming
suggestions.
314
      // Theme implementations can occur in multiple paths. Suggestions
should follow.
31591
      if (!isset($info['theme paths']) && isset($cache[$hook])) {
31691
        $result[$hook]['theme paths'] = $cache[$hook]['theme paths'];
31791
      }
318
      // Check for sub-directories.
31991
      $result[$hook]['theme paths'][] = isset($info['path']) ?
$info['path'] : $path;
320
321
      // Check for default _preprocess_ functions. Ensure arrayness.
32291
      if (!isset($info['preprocess functions']) ||
!is_array($info['preprocess functions'])) {
32391
        $info['preprocess functions'] = array();
32491
        $prefixes = array();
32591
        if ($type == 'module') {
326
          // Default preprocessor prefix.
32791
          $prefixes[] = 'template';
328
          // Add all modules so they can intervene with their own
preprocessors. This allows them
329
          // to provide preprocess functions even if they are not the owner
of the current hook.
33091
          $prefixes += module_list();
33191
        }
33291
        elseif ($type == 'theme_engine') {
333
          // Theme engines get an extra set that come before the normally
named preprocessors.
33491
          $prefixes[] = $name . '_engine';
335
          // The theme engine also registers on behalf of the theme. The
theme or engine name can be used.
33691
          $prefixes[] = $name;
33791
          $prefixes[] = $theme;
33891
        }
339
        else {
340
          // This applies when the theme manually registers their own
preprocessors.
3410
          $prefixes[] = $name;
342
        }
343
34491
        foreach ($prefixes as $prefix) {
34591
          if (function_exists($prefix . '_preprocess')) {
34691
            $info['preprocess functions'][] = $prefix . '_preprocess';
34791
          }
34891
          if (function_exists($prefix . '_preprocess_' . $hook)) {
34991
            $info['preprocess functions'][] = $prefix . '_preprocess_' .
$hook;
35091
          }
35191
        }
35291
      }
353
      // Check for the override flag and prevent the cached preprocess
functions from being used.
354
      // This allows themes or theme engines to remove preprocessors set
earlier in the registry build.
35591
      if (!empty($info['override preprocess functions'])) {
356
        // Flag not needed inside the registry.
3570
        unset($result[$hook]['override preprocess functions']);
3580
      }
35991
      elseif (isset($cache[$hook]['preprocess functions']) &&
is_array($cache[$hook]['preprocess functions'])) {
36091
        $info['preprocess functions'] =
array_merge($cache[$hook]['preprocess functions'], $info['preprocess
functions']);
36191
      }
36291
      $result[$hook]['preprocess functions'] = $info['preprocess
functions'];
36391
    }
364
365
    // Merge the newly created theme hooks into the existing cache.
36691
    $cache = array_merge($cache, $result);
36791
  }
36891
}
369
370
/**
371
 * Rebuild the hook theme_registry cache.
372
 *
373
 * @param $theme
374
 *   The loaded $theme object.
375
 * @param $base_theme
376
 *   An array of loaded $theme objects representing the ancestor themes in
377
 *   oldest first order.
378
 * @param theme_engine
379
 *   The name of the theme engine.
380
 */
3812027
function _theme_build_registry($theme, $base_theme, $theme_engine) {
38291
  $cache = array();
383
  // First, process the theme hooks advertised by modules. This will
384
  // serve as the basic registry.
38591
  foreach (module_implements('theme') as $module) {
38691
    _theme_process_registry($cache, $module, 'module', $module,
drupal_get_path('module', $module));
38791
  }
388
389
  // Process each base theme.
39091
  foreach ($base_theme as $base) {
391
    // If the theme uses a theme engine, process its hooks.
3920
    $base_path = dirname($base->filename);
3930
    if ($theme_engine) {
3940
      _theme_process_registry($cache, $theme_engine, 'base_theme_engine',
$base->name, $base_path);
3950
    }
3960
    _theme_process_registry($cache, $base->name, 'base_theme', $base->name,
$base_path);
3970
  }
398
399
  // And then the same thing, but for the theme.
40091
  if ($theme_engine) {
40191
    _theme_process_registry($cache, $theme_engine, 'theme_engine',
$theme->name, dirname($theme->filename));
40291
  }
403
404
  // Finally, hooks provided by the theme itself.
40591
  _theme_process_registry($cache, $theme->name, 'theme', $theme->name,
dirname($theme->filename));
406
407
  // Let modules alter the registry
40891
  drupal_alter('theme_registry', $cache);
40991
  return $cache;
4100
}
411
412
/**
413
 * Provides a list of currently available themes.
414
 *
415
 * If the database is active then it will be retrieved from the database.
416
 * Otherwise it will retrieve a new list.
417
 *
418
 * @param $refresh
419
 *   Whether to reload the list of themes from the database.
420
 * @return
421
 *   An array of the currently available themes.
422
 */
4232027
function list_themes($refresh = FALSE) {
4242087
  static $list = array();
425
4262087
  if ($refresh) {
4270
    $list = array();
4280
  }
429
4302087
  if (empty($list)) {
4312027
    $list = array();
4322027
    $themes = array();
433
    // Extract from the database only when it is available.
434
    // Also check that the site is not in the middle of an install or
update.
4352027
    if (db_is_active() && !defined('MAINTENANCE_MODE')) {
4362027
      $result = db_query("SELECT * FROM {system} WHERE type = '%s'",
'theme');
4372027
      while ($theme = db_fetch_object($result)) {
4382027
        if (file_exists($theme->filename)) {
4392027
          $theme->info = unserialize($theme->info);
4402027
          $themes[] = $theme;
4412027
        }
4422027
      }
4432027
    }
444
    else {
445
      // Scan the installation when the database should not be read.
4460
      $themes = _system_theme_data();
447
    }
448
4492027
    foreach ($themes as $theme) {
4502027
      foreach ($theme->info['stylesheets'] as $media => $stylesheets) {
4512027
        foreach ($stylesheets as $stylesheet => $path) {
4522027
          $theme->stylesheets[$media][$stylesheet] = $path;
4532027
        }
4542027
      }
4552027
      foreach ($theme->info['scripts'] as $script => $path) {
4562027
        if (file_exists($path)) {
4570
          $theme->scripts[$script] = $path;
4580
        }
4592027
      }
4602027
      if (isset($theme->info['engine'])) {
4612027
        $theme->engine = $theme->info['engine'];
4622027
      }
4632027
      if (isset($theme->info['base theme'])) {
4642027
        $theme->base_theme = $theme->info['base theme'];
4652027
      }
466
      // Status is normally retrieved from the database. Add zero values
when
467
      // read from the installation directory to prevent notices.
4682027
      if (!isset($theme->status)) {
4690
        $theme->status = 0;
4700
      }
4712027
      $list[$theme->name] = $theme;
4722027
    }
4732027
  }
474
4752087
  return $list;
4760
}
477
478
/**
479
 * Generate the themed output.
480
 *
481
 * All requests for theme hooks must go through this function. It examines
482
 * the request and routes it to the appropriate theme function. The theme
483
 * registry is checked to determine which implementation to use, which may
484
 * be a function or a template.
485
 *
486
 * If the implementation is a function, it is executed and its return
value
487
 * passed along.
488
 *
489
 * If the implementation is a template, the arguments are converted to a
490
 * $variables array. This array is then modified by the module
implementing
491
 * the hook, theme engine (if applicable) and the theme. The following
492
 * functions may be used to modify the $variables array. They are processed
in
493
 * this order when available:
494
 *
495
 * - template_preprocess(&$variables)
496
 *   This sets a default set of variables for all template
implementations.
497
 *
498
 * - template_preprocess_HOOK(&$variables)
499
 *   This is the first preprocessor called specific to the hook; it should
be
500
 *   implemented by the module that registers it.
501
 *
502
 * - MODULE_preprocess(&$variables)
503
 *   This will be called for all templates; it should only be used if
there
504
 *   is a real need. It's purpose is similar to template_preprocess().
505
 *
506
 * - MODULE_preprocess_HOOK(&$variables)
507
 *   This is for modules that want to alter or provide extra variables for
508
 *   theming hooks not registered to itself. For example, if a module
named
509
 *   "foo" wanted to alter the $submitted variable for the hook "node" a
510
 *   preprocess function of foo_preprocess_node() can be created to
intercept
511
 *   and alter the variable.
512
 *
513
 * - ENGINE_engine_preprocess(&$variables)
514
 *   This function should only be implemented by theme engines and exists
515
 *   so that it can set necessary variables for all hooks.
516
 *
517
 * - ENGINE_engine_preprocess_HOOK(&$variables)
518
 *   This is the same as the previous function, but it is called for a
single
519
 *   theming hook.
520
 *
521
 * - ENGINE_preprocess(&$variables)
522
 *   This is meant to be used by themes that utilize a theme engine. It is
523
 *   provided so that the preprocessor is not locked into a specific
theme.
524
 *   This makes it easy to share and transport code but theme authors must
be
525
 *   careful to prevent fatal re-declaration errors when using sub-themes
that
526
 *   have their own preprocessor named exactly the same as its base theme.
In
527
 *   the default theme engine (PHPTemplate), sub-themes will load their
own
528
 *   template.php file in addition to the one used for its parent theme.
This
529
 *   increases the risk for these errors. A good practice is to use the
engine
530
 *   name for the base theme and the theme name for the sub-themes to
minimize
531
 *   this possibility.
532
 *
533
 * - ENGINE_preprocess_HOOK(&$variables)
534
 *   The same applies from the previous function, but it is called for a
535
 *   specific hook.
536
 *
537
 * - THEME_preprocess(&$variables)
538
 *   These functions are based upon the raw theme; they should primarily
be
539
 *   used by themes that do not use an engine or by sub-themes. It serves
the
540
 *   same purpose as ENGINE_preprocess().
541
 *
542
 * - THEME_preprocess_HOOK(&$variables)
543
 *   The same applies from the previous function, but it is called for a
544
 *   specific hook.
545
 *
546
 * There are two special variables that these hooks can set:
547
 *   'template_file' and 'template_files'. These will be merged together
548
 *   to form a list of 'suggested' alternate template files to use, in
549
 *   reverse order of priority. template_file will always be a higher
550
 *   priority than items in template_files. theme() will then look for
these
551
 *   files, one at a time, and use the first one
552
 *   that exists.
553
 * @param $hook
554
 *   The name of the theme function to call. May be an array, in which
555
 *   case the first hook that actually has an implementation registered
556
 *   will be used. This can be used to choose 'fallback' theme
implementations,
557
 *   so that if the specific theme hook isn't implemented anywhere, a more
558
 *   generic one will be used. This can allow themes to create specific
theme
559
 *   implementations for named objects.
560
 * @param ...
561
 *   Additional arguments to pass along to the theme function.
562
 * @return
563
 *   An HTML string that generates the themed output.
564
 */
5652027
function theme() {
5662087
  $args = func_get_args();
5672087
  $hook = array_shift($args);
568
5692087
  static $hooks = NULL;
5702087
  if (!isset($hooks)) {
5712027
    init_theme();
5722027
    $hooks = theme_get_registry();
5732027
  }
574
5752087
  if (is_array($hook)) {
57686
    foreach ($hook as $candidate) {
57786
      if (isset($hooks[$candidate])) {
57886
        break;
5790
      }
58086
    }
58186
    $hook = $candidate;
58286
  }
583
5842087
  if (!isset($hooks[$hook])) {
585416
    return;
5860
  }
587
5882087
  $info = $hooks[$hook];
5892087
  global $theme_path;
5902087
  $temp = $theme_path;
591
  // point path_to_theme() to the currently used theme path:
5922087
  $theme_path = $info['theme path'];
593
594
  // Include a file if the theme function or preprocess function is held
elsewhere.
5952087
  if (!empty($info['file'])) {
596466
    $include_file = $info['file'];
597466
    if (isset($info['path'])) {
5980
      $include_file = $info['path'] . '/' . $include_file;
5990
    }
600466
    include_once($include_file);
601466
  }
6022087
  if (isset($info['function'])) {
603
    // The theme call is a function.
6042087
    $output = call_user_func_array($info['function'], $args);
6052087
  }
606
  else {
607
    // The theme call is a template.
608
    $variables = array(
6091510
      'template_files' => array()
6101510
    );
6111510
    if (!empty($info['arguments'])) {
6121510
      $count = 0;
6131510
      foreach ($info['arguments'] as $name => $default) {
6141510
        $variables[$name] = isset($args[$count]) ? $args[$count] :
$default;
6151510
        $count++;
6161510
      }
6171510
    }
618
619
    // default render function and extension.
6201510
    $render_function = 'theme_render_template';
6211510
    $extension = '.tpl.php';
622
623
    // Run through the theme engine variables, if necessary
6241510
    global $theme_engine;
6251510
    if (isset($theme_engine)) {
626
      // If theme or theme engine is implementing this, it may have
627
      // a different extension and a different renderer.
6281510
      if ($info['type'] != 'module') {
6291501
        if (function_exists($theme_engine . '_render_template')) {
6300
          $render_function = $theme_engine . '_render_template';
6310
        }
6321501
        $extension_function = $theme_engine . '_extension';
6331501
        if (function_exists($extension_function)) {
6340
          $extension = $extension_function();
6350
        }
6361501
      }
6371510
    }
638
6391510
    if (isset($info['preprocess functions']) && is_array($info['preprocess
functions'])) {
640
      // This construct ensures that we can keep a reference through
641
      // call_user_func_array.
6421510
      $args = array(&$variables, $hook);
6431510
      foreach ($info['preprocess functions'] as $preprocess_function) {
6441510
        if (drupal_function_exists($preprocess_function)) {
6451510
          call_user_func_array($preprocess_function, $args);
6461510
        }
6471510
      }
6481510
    }
649
650
    // Get suggestions for alternate templates out of the variables
651
    // that were set. This lets us dynamically choose a template
652
    // from a list. The order is FILO, so this array is ordered from
653
    // least appropriate first to most appropriate last.
6541510
    $suggestions = array();
655
6561510
    if (isset($variables['template_files'])) {
6571510
      $suggestions = $variables['template_files'];
6581510
    }
6591510
    if (isset($variables['template_file'])) {
6600
      $suggestions[] = $variables['template_file'];
6610
    }
662
6631510
    if ($suggestions) {
6641501
      $template_file = drupal_discover_template($info['theme paths'],
$suggestions, $extension);
6651501
    }
666
6671510
    if (empty($template_file)) {
6681510
      $template_file = $info['template'] . $extension;
6691510
      if (isset($info['path'])) {
6701501
        $template_file = $info['path'] . '/' . $template_file;
6711501
      }
6721510
    }
6731510
    $output = $render_function($template_file, $variables);
674
  }
675
  // restore path_to_theme()
6762087
  $theme_path = $temp;
6772087
  return $output;
6780
}
679
680
/**
681
 * Choose which template file to actually render. These are all suggested
682
 * templates from themes and modules. Theming implementations can occur on
683
 * multiple levels. All paths are checked to account for this.
684
 */
6852027
function drupal_discover_template($paths, $suggestions, $extension =
'.tpl.php') {
6861501
  global $theme_engine;
687
688
  // Loop through all paths and suggestions in FIFO order.
6891501
  $suggestions = array_reverse($suggestions);
6901501
  $paths = array_reverse($paths);
6911501
  foreach ($suggestions as $suggestion) {
6921501
    if (!empty($suggestion)) {
6931501
      foreach ($paths as $path) {
6941501
        if (file_exists($file = $path . '/' . $suggestion . $extension)) {
6950
          return $file;
6960
        }
6971501
      }
6981501
    }
6991501
  }
7001501
}
701
702
/**
703
 * Return the path to the currently selected theme.
704
 */
7052027
function path_to_theme() {
7061510
  global $theme_path;
707
7081510
  if (!isset($theme_path)) {
7090
    init_theme();
7100
  }
711
7121510
  return $theme_path;
7130
}
714
715
/**
716
 * Find overridden theme functions. Called by themes and/or theme engines
to
717
 * easily discover theme functions.
718
 *
719
 * @param $cache
720
 *   The existing cache of theme hooks to test against.
721
 * @param $prefixes
722
 *   An array of prefixes to test, in reverse order of importance.
723
 *
724
 * @return $templates
725
 *   The functions found, suitable for returning from hook_theme;
726
 */
7272027
function drupal_find_theme_functions($cache, $prefixes) {
72891
  $templates = array();
72991
  $functions = get_defined_functions();
730
73191
  foreach ($cache as $hook => $info) {
73291
    foreach ($prefixes as $prefix) {
73391
      if (!empty($info['pattern'])) {
7340
        $matches = preg_grep('/^' . $prefix . '_' . $info['pattern'] . '/',
$functions['user']);
7350
        if ($matches) {
7360
          foreach ($matches as $match) {
7370
            $new_hook = str_replace($prefix . '_', '', $match);
7380
            $templates[$new_hook] = array(
7390
              'function' => $match,
7400
              'arguments' => $info['arguments'],
741
            );
7420
          }
7430
        }
7440
      }
74591
      if (function_exists($prefix . '_' . $hook)) {
74691
        $templates[$hook] = array(
74791
          'function' => $prefix . '_' . $hook,
748
        );
74991
      }
75091
    }
75191
  }
752
75391
  return $templates;
7540
}
755
756
/**
757
 * Find overridden theme templates. Called by themes and/or theme engines
to
758
 * easily discover templates.
759
 *
760
 * @param $cache
761
 *   The existing cache of theme hooks to test against.
762
 * @param $extension
763
 *   The extension that these templates will have.
764
 * @param $path
765
 *   The path to search.
766
 */
7672027
function drupal_find_theme_templates($cache, $extension, $path) {
76891
  $templates = array();
769
770
  // Collect paths to all sub-themes grouped by base themes. These will be
771
  // used for filtering. This allows base themes to have sub-themes in its
772
  // folder hierarchy without affecting the base themes template
discovery.
77391
  $theme_paths = array();
77491
  foreach (list_themes() as $theme_info) {
77591
    if (!empty($theme_info->base_theme)) {
77691
      $theme_paths[$theme_info->base_theme][$theme_info->name] =
dirname($theme_info->filename);
77791
    }
77891
  }
77991
  foreach ($theme_paths as $basetheme => $subthemes) {
78091
    foreach ($subthemes as $subtheme => $subtheme_path) {
78191
      if (isset($theme_paths[$subtheme])) {
7820
        $theme_paths[$basetheme] = array_merge($theme_paths[$basetheme],
$theme_paths[$subtheme]);
7830
      }
78491
    }
78591
  }
78691
  global $theme;
78791
  $subtheme_paths = isset($theme_paths[$theme]) ? $theme_paths[$theme] :
array();
788
789
  // Escape the periods in the extension.
79091
  $regex = str_replace('.', '\.', $extension) . '$';
791
  // Because drupal_system_listing works the way it does, we check for
real
792
  // templates separately from checking for patterns.
79391
  $files = drupal_system_listing($regex, $path, 'name', 0);
79491
  foreach ($files as $template => $file) {
795
    // Ignore sub-theme templates for the current theme.
79691
    if (strpos($file->filename, str_replace($subtheme_paths, '',
$file->filename)) !== 0) {
7970
      continue;
7980
    }
799
    // Chop off the remaining extensions if there are any. $template
already
800
    // has the rightmost extension removed, but there might still be more,
801
    // such as with .tpl.php, which still has .tpl in $template at this
point.
80291
    if (($pos = strpos($template, '.')) !== FALSE) {
80391
      $template = substr($template, 0, $pos);
80491
    }
805
    // Transform - in filenames to _ to match function naming scheme
806
    // for the purposes of searching.
80791
    $hook = strtr($template, '-', '_');
80891
    if (isset($cache[$hook])) {
80991
      $templates[$hook] = array(
81091
        'template' => $template,
81191
        'path' => dirname($file->filename),
812
      );
81391
    }
81491
  }
815
81691
  $patterns = array_keys($files);
817
81891
  foreach ($cache as $hook => $info) {
81991
    if (!empty($info['pattern'])) {
820
      // Transform _ in pattern to - to match file naming scheme
821
      // for the purposes of searching.
8220
      $pattern = strtr($info['pattern'], '_', '-');
823
8240
      $matches = preg_grep('/^' . $pattern . '/', $patterns);
8250
      if ($matches) {
8260
        foreach ($matches as $match) {
8270
          $file = substr($match, 0, strpos($match, '.'));
828
          // Put the underscores back in for the hook name and register
this pattern.
8290
          $templates[strtr($file, '-', '_')] = array(
8300
            'template' => $file,
8310
            'path' => dirname($files[$match]->filename),
8320
            'arguments' => $info['arguments'],
833
          );
8340
        }
8350
      }
8360
    }
83791
  }
83891
  return $templates;
8390
}
840
841
/**
842
 * Retrieve an associative array containing the settings for a theme.
843
 *
844
 * The final settings are arrived at by merging the default settings,
845
 * the site-wide settings, and the settings defined for the specific
theme.
846
 * If no $key was specified, only the site-wide theme defaults are
retrieved.
847
 *
848
 * The default values for each of settings are also defined in this
function.
849
 * To add new settings, add their default values here, and then add form
elements
850
 * to system_theme_settings() in system.module.
851
 *
852
 * @param $key
853
 *  The template/style value for a given theme.
854
 *
855
 * @return
856
 *   An associative array containing theme settings.
857
 */
8582027
function theme_get_settings($key = NULL) {
859
  $defaults = array(
8601501
    'mission'                       =>  '',
8611501
    'default_logo'                  =>  1,
8621501
    'logo_path'                     =>  '',
8631501
    'default_favicon'               =>  1,
8641501
    'favicon_path'                  =>  '',
8651501
    'main_menu'                     =>  1,
8661501
    'secondary_menu'                =>  1,
8671501
    'toggle_logo'                   =>  1,
8681501
    'toggle_favicon'                =>  1,
8691501
    'toggle_name'                   =>  1,
8701501
    'toggle_search'                 =>  1,
8711501
    'toggle_slogan'                 =>  0,
8721501
    'toggle_mission'                =>  1,
8731501
    'toggle_node_user_picture'      =>  0,
8741501
    'toggle_comment_user_picture'   =>  0,
8751501
    'toggle_main_menu'              =>  1,
8761501
    'toggle_secondary_menu'         =>  1,
8771501
  );
878
8791501
  if (module_exists('node')) {
8801501
    foreach (node_get_types() as $type => $name) {
8811501
      $defaults['toggle_node_info_' . $type] = 1;
8821501
    }
8831501
  }
8841501
  $settings = array_merge($defaults, variable_get('theme_settings',
array()));
885
8861501
  if ($key) {
8871501
    $settings = array_merge($settings, variable_get(str_replace('/', '_',
'theme_' . $key . '_settings'), array()));
8881501
  }
889
890
  // Only offer search box if search.module is enabled.
8911501
  if (!module_exists('search') || !user_access('search content')) {
8921497
    $settings['toggle_search'] = 0;
8931497
  }
894
8951501
  return $settings;
8960
}
897
898
/**
899
 * Retrieve a setting for the current theme.
900
 * This function is designed for use from within themes & engines
901
 * to determine theme settings made in the admin interface.
902
 *
903
 * Caches values for speed (use $refresh = TRUE to refresh cache)
904
 *
905
 * @param $setting_name
906
 *  The name of the setting to be retrieved.
907
 *
908
 * @param $refresh
909
 *  Whether to reload the cache of settings.
910
 *
911
 * @return
912
 *   The value of the requested setting, NULL if the setting does not
exist.
913
 */
9142027
function theme_get_setting($setting_name, $refresh = FALSE) {
9151501
  global $theme_key;
9161501
  static $settings;
917
9181501
  if (empty($settings) || $refresh) {
9191501
    $settings = theme_get_settings($theme_key);
920
9211501
    $themes = list_themes();
9221501
    $theme_object = $themes[$theme_key];
923
9241501
    if ($settings['mission'] == '') {
9251501
      $settings['mission'] = variable_get('site_mission', '');
9261501
    }
927
9281501
    if (!$settings['toggle_mission']) {
9290
      $settings['mission'] = '';
9300
    }
931
9321501
    if ($settings['toggle_logo']) {
9331501
      if ($settings['default_logo']) {
9341501
        $settings['logo'] = base_path() . dirname($theme_object->filename)
. '/logo.png';
9351501
      }
9360
      elseif ($settings['logo_path']) {
9370
        $settings['logo'] = base_path() . $settings['logo_path'];
9380
      }
9391501
    }
940
9411501
    if ($settings['toggle_favicon']) {
9421501
      if ($settings['default_favicon']) {
9431501
        if (file_exists($favicon = dirname($theme_object->filename) .
'/favicon.ico')) {
9440
          $settings['favicon'] = base_path() . $favicon;
9450
        }
946
        else {
9471501
          $settings['favicon'] = base_path() . 'misc/favicon.ico';
948
        }
9491501
      }
9500
      elseif ($settings['favicon_path']) {
9510
        $settings['favicon'] = base_path() . $settings['favicon_path'];
9520
      }
953
      else {
9540
        $settings['toggle_favicon'] = FALSE;
955
      }
9561501
    }
9571501
  }
958
9591501
  return isset($settings[$setting_name]) ? $settings[$setting_name] :
NULL;
9600
}
961
962
/**
963
 * Render a system default template, which is essentially a PHP template.
964
 *
965
 * @param $file
966
 *   The filename of the template to render.
967
 * @param $variables
968
 *   A keyed array of variables that will appear in the output.
969
 *
970
 * @return
971
 *   The output generated by the template.
972
 */
9732027
function theme_render_template($file, $variables) {
9741510
  extract($variables, EXTR_SKIP);  // Extract the variables to a local
namespace
9751510
  ob_start();                      // Start output buffering
9761510
  include "./$file";               // Include the file
9771510
  $contents = ob_get_contents();   // Get the contents of the buffer
9781510
  ob_end_clean();                  // End buffering and discard
9791510
  return $contents;                // Return the contents
9800
}
981
982
/**
983
 * @defgroup themeable Default theme implementations
984
 * @{
985
 * Functions and templates that present output to the user, and can be
986
 * implemented by themes.
987
 *
988
 * Drupal's presentation layer is a pluggable system known as the theme
989
 * layer. Each theme can take control over most of Drupal's output, and
990
 * has complete control over the CSS.
991
 *
992
 * Inside Drupal, the theme layer is utilized by the use of the theme()
993
 * function, which is passed the name of a component (the theme hook)
994
 * and several arguments. For example, theme('table', $header, $rows);
995
 * Additionally, the theme() function can take an array of theme
996
 * hooks, which can be used to provide 'fallback' implementations to
997
 * allow for more specific control of output. For example, the function:
998
 * theme(array('table__foo', 'table'), $header, $rows) would look to see
if
999
 * 'table__foo' is registered anywhere; if it is not, it would 'fall back'
1000
 * to the generic 'table' implementation. This can be used to attach
specific
1001
 * theme functions to named objects, allowing the themer more control over
1002
 * specific types of output.
1003
 *
1004
 * As of Drupal 6, every theme hook is required to be registered by the
1005
 * module that owns it, so that Drupal can tell what to do with it and
1006
 * to make it simple for themes to identify and override the behavior
1007
 * for these calls.
1008
 *
1009
 * The theme hooks are registered via hook_theme(), which returns an
1010
 * array of arrays with information about the hook. It describes the
1011
 * arguments the function or template will need, and provides
1012
 * defaults for the template in case they are not filled in. If the
default
1013
 * implementation is a function, by convention it is named theme_HOOK().
1014
 *
1015
 * Each module should provide a default implementation for theme_hooks
that
1016
 * it registers. This implementation may be either a function or a
template;
1017
 * if it is a function it must be specified via hook_theme(). By
convention,
1018
 * default implementations of theme hooks are named theme_HOOK. Default
1019
 * template implementations are stored in the module directory.
1020
 *
1021
 * Drupal's default template renderer is a simple PHP parsing engine that
1022
 * includes the template and stores the output. Drupal's theme engines
1023
 * can provide alternate template engines, such as XTemplate, Smarty and
1024
 * PHPTal. The most common template engine is PHPTemplate (included with
1025
 * Drupal and implemented in phptemplate.engine, which uses Drupal's
default
1026
 * template renderer.
1027
 *
1028
 * In order to create theme-specific implementations of these hooks,
1029
 * themes can implement their own version of theme hooks, either as
functions
1030
 * or templates. These implementations will be used instead of the default
1031
 * implementation. If using a pure .theme without an engine, the .theme is
1032
 * required to implement its own version of hook_theme() to tell Drupal
what
1033
 * it is implementing; themes utilizing an engine will have their
well-named
1034
 * theming functions automatically registered for them. While this can
vary
1035
 * based upon the theme engine, the standard set by phptemplate is that
theme
1036
 * functions should be named either phptemplate_HOOK or THEMENAME_HOOK.
For
1037
 * example, for Drupal's default theme (Garland) to implement the 'table'
hook,
1038
 * the phptemplate.engine would find phptemplate_table() or
garland_table().
1039
 * The ENGINE_HOOK() syntax is preferred, as this can be used by
sub-themes
1040
 * (which are themes that share code but use different stylesheets).
1041
 *
1042
 * The theme system is described and defined in theme.inc.
1043
 *
1044
 * @see theme()
1045
 * @see hook_theme()
1046
 */
1047
1048
/**
1049
 * Formats text for emphasized display in a placeholder inside a sentence.
1050
 * Used automatically by t().
1051
 *
1052
 * @param $text
1053
 *   The text to format (plain-text).
1054
 * @return
1055
 *   The formatted text (html).
1056
 */
10572027
function theme_placeholder($text) {
1058507
  return '<em>' . check_plain($text) . '</em>';
10590
}
1060
1061
/**
1062
 * Return a themed set of status and/or error messages. The messages are
grouped
1063
 * by type.
1064
 *
1065
 * @param $display
1066
 *   (optional) Set to 'status' or 'error' to display only messages of that
type.
1067
 *
1068
 * @return
1069
 *   A string containing the messages.
1070
 */
10712027
function theme_status_messages($display = NULL) {
10721489
  $output = '';
10731489
  foreach (drupal_get_messages($display) as $type => $messages) {
1074291
    $output .= "<div class=\"messages $type\">\n";
1075291
    if (count($messages) > 1) {
10765
      $output .= " <ul>\n";
10775
      foreach ($messages as $message) {
10785
        $output .= '  <li>' . $message . "</li>\n";
10795
      }
10805
      $output .= " </ul>\n";
10815
    }
1082
    else {
1083287
      $output .= $messages[0];
1084
    }
1085291
    $output .= "</div>\n";
1086291
  }
10871489
  return $output;
10880
}
1089
1090
/**
1091
 * Return a themed set of links.
1092
 *
1093
 * @param $links
1094
 *   A keyed array of links to be themed.
1095
 * @param $attributes
1096
 *   A keyed array of attributes
1097
 * @return
1098
 *   A string containing an unordered list of links.
1099
 */
11002027
function theme_links($links, $attributes = array('class' => 'links')) {
11011501
  $output = '';
1102
11031501
  if (count($links) > 0) {
1104199
    $output = '<ul' . drupal_attributes($attributes) . '>';
1105
1106199
    $num_links = count($links);
1107199
    $i = 1;
1108
1109199
    foreach ($links as $key => $link) {
1110199
      $class = $key;
1111
1112
      // Add first, last and active classes to the list of links to help
out themers.
1113199
      if ($i == 1) {
1114199
        $class .= ' first';
1115199
      }
1116199
      if ($i == $num_links) {
1117199
        $class .= ' last';
1118199
      }
1119199
      if (isset($link['href']) && ($link['href'] == $_GET['q'] ||
($link['href'] == '<front>' && drupal_is_front_page()))) {
112034
        $class .= ' active';
112134
      }
1122199
      $output .= '<li' . drupal_attributes(array('class' => $class)) .
'>';
1123
1124199
      if (isset($link['href'])) {
1125
        // Pass in $link as $options, they share the same keys.
1126199
        $output .= l($link['title'], $link['href'], $link);
1127199
      }
11280
      else if (!empty($link['title'])) {
1129
        // Some links are actually not links, but we wrap these in <span>
for adding title and class attributes
11300
        if (empty($link['html'])) {
11310
          $link['title'] = check_plain($link['title']);
11320
        }
11330
        $span_attributes = '';
11340
        if (isset($link['attributes'])) {
11350
          $span_attributes = drupal_attributes($link['attributes']);
11360
        }
11370
        $output .= '<span' . $span_attributes . '>' . $link['title'] .
'</span>';
11380
      }
1139
1140199
      $i++;
1141199
      $output .= "</li>\n";
1142199
    }
1143
1144199
    $output .= '</ul>';
1145199
  }
1146
11471501
  return $output;
11480
}
1149
1150
/**
1151
 * Return a themed image.
1152
 *
1153
 * @param $path
1154
 *   Either the path of the image file (relative to base_path()) or a full
URL.
1155
 * @param $alt
1156
 *   The alternative text for text-based browsers.
1157
 * @param $title
1158
 *   The title text is displayed when the image is hovered in some popular
browsers.
1159
 * @param $attributes
1160
 *   Associative array of attributes to be placed in the img tag.
1161
 * @param $getsize
1162
 *   If set to TRUE, the image's dimension are fetched and added as
width/height attributes.
1163
 * @return
1164
 *   A string containing the image tag.
1165
 */
11662027
function theme_image($path, $alt = '', $title = '', $attributes = NULL,
$getsize = TRUE) {
11671489
  if (!$getsize || (is_file($path) && (list($width, $height, $type,
$image_attributes) = @getimagesize($path)))) {
11681489
    $attributes = drupal_attributes($attributes);
11691489
    $url = (url($path) == $path) ? $path : (base_path() . $path);
11701489
    return '<img src="' . check_url($url) . '" alt="' . check_plain($alt) .
'" title="' . check_plain($title) . '" ' . (isset($image_attributes) ?
$image_attributes : '') . $attributes . ' />';
11710
  }
11720
}
1173
1174
/**
1175
 * Return a themed breadcrumb trail.
1176
 *
1177
 * @param $breadcrumb
1178
 *   An array containing the breadcrumb links.
1179
 * @return a string containing the breadcrumb output.
1180
 */
11812027
function theme_breadcrumb($breadcrumb) {
11820
  if (!empty($breadcrumb)) {
11830
    return '<div class="breadcrumb">' . implode(' ยป ', $breadcrumb) .
'</div>';
11840
  }
11850
}
1186
1187
/**
1188
 * Return a themed help message.
1189
 *
1190
 * @return a string containing the helptext for the current page.
1191
 */
11922027
function theme_help() {
11931489
  if ($help = menu_get_active_help()) {
1194294
    return '<div class="help">' . $help . '</div>';
11950
  }
11961195
}
1197
1198
/**
1199
 * Return a themed submenu, typically displayed under the tabs.
1200
 *
1201
 * @param $links
1202
 *   An array of links.
1203
 */
12042027
function theme_submenu($links) {
12050
  return '<div class="submenu">' . implode(' | ', $links) . '</div>';
12060
}
1207
1208
/**
1209
 * Return a themed table.
1210
 *
1211
 * @param $header
1212
 *   An array containing the table headers. Each element of the array can
be
1213
 *   either a localized string or an associative array with the following
keys:
1214
 *   - "data": The localized title of the table column.
1215
 *   - "field": The database field represented in the table column
(required if
1216
 *     user is to be able to sort on this column).
1217
 *   - "sort": A default sort order for this column ("asc" or "desc").
1218
 *   - Any HTML attributes, such as "colspan", to apply to the column
header cell.
1219
 * @param $rows
1220
 *   An array of table rows. Every row is an array of cells, or an
associative
1221
 *   array with the following keys:
1222
 *   - "data": an array of cells
1223
 *   - Any HTML attributes, such as "class", to apply to the table row.
1224
 *
1225
 *   Each cell can be either a string or an associative array with the
following keys:
1226
 *   - "data": The string to display in the table cell.
1227
 *   - "header": Indicates this cell is a header.
1228
 *   - Any HTML attributes, such as "colspan", to apply to the table cell.
1229
 *
1230
 *   Here's an example for $rows:
1231
 *   @verbatim
1232
 *   $rows = array(
1233
 *     // Simple row
1234
 *     array(
1235
 *       'Cell 1', 'Cell 2', 'Cell 3'
1236
 *     ),
1237
 *     // Row with attributes on the row and some of its cells.
1238
 *     array(
1239
 *       'data' => array('Cell 1', array('data' => 'Cell 2', 'colspan' =>
2)), 'class' => 'funky'
1240
 *     )
1241
 *   );
1242
 *   @endverbatim
1243
 *
1244
 * @param $attributes
1245
 *   An array of HTML attributes to apply to the table tag.
1246
 * @param $caption
1247
 *   A localized string to use for the <caption> tag.
1248
 * @param $colgroups
1249
 *   An array of column groups. Each element of the array can be either:
1250
 *   - An array of columns, each of which is an associative array of HTML
attributes
1251
 *     applied to the COL element.
1252
 *   - An array of attributes applied to the COLGROUP element, which must
include a
1253
 *     "data" attribute. To add attributes to COL elements, set the "data"
attribute
1254
 *     with an array of columns, each of which is an associative array of
HTML attributes.
1255
 *   Here's an example for $colgroup:
1256
 *   @verbatim
1257
 *   $colgroup = array(
1258
 *     // COLGROUP with one COL element.
1259
 *     array(
1260
 *       array(
1261
 *         'class' => 'funky', // Attribute for the COL element.
1262
 *       ),
1263
 *     ),
1264
 *     // Colgroup with attributes and inner COL elements.
1265
 *     array(
1266
 *       'data' => array(
1267
 *         array(
1268
 *           'class' => 'funky', // Attribute for the COL element.
1269
 *         ),
1270
 *       ),
1271
 *       'class' => 'jazzy', // Attribute for the COLGROUP element.
1272
 *     ),
1273
 *   );
1274
 *   @endverbatim
1275
 *   These optional tags are used to group and set properties on columns
1276
 *   within a table. For example, one may easily group three columns and
1277
 *   apply same background style to all.
1278
 * @return
1279
 *   An HTML string representing the table.
1280
 */
12812027
function theme_table($header, $rows, $attributes = array(), $caption =
NULL, $colgroups = array()) {
1282
1283
  // Add sticky headers, if applicable.
1284232
  if (count($header)) {
1285232
    drupal_add_js('misc/tableheader.js');
1286
    // Add 'sticky-enabled' class to the table to identify it for JS.
1287
    // This is needed to target tables constructed by this function.
1288232
    $attributes['class'] = empty($attributes['class']) ? 'sticky-enabled' :
($attributes['class'] . ' sticky-enabled');
1289232
  }
1290
1291232
  $output = '<table' . drupal_attributes($attributes) . ">\n";
1292
1293232
  if (isset($caption)) {
12940
    $output .= '<caption>' . $caption . "</caption>\n";
12950
  }
1296
1297
  // Format the table columns:
1298232
  if (count($colgroups)) {
12990
    foreach ($colgroups as $number => $colgroup) {
13000
      $attributes = array();
1301
1302
      // Check if we're dealing with a simple or complex column
13030
      if (isset($colgroup['data'])) {
13040
        foreach ($colgroup as $key => $value) {
13050
          if ($key == 'data') {
13060
            $cols = $value;
13070
          }
1308
          else {
13090
            $attributes[$key] = $value;
1310
          }
13110
        }
13120
      }
1313
      else {
13140
        $cols = $colgroup;
1315
      }
1316
1317
      // Build colgroup
13180
      if (is_array($cols) && count($cols)) {
13190
        $output .= ' <colgroup' . drupal_attributes($attributes) . '>';
13200
        $i = 0;
13210
        foreach ($cols as $col) {
13220
          $output .= ' <col' . drupal_attributes($col) . ' />';
13230
        }
13240
        $output .= " </colgroup>\n";
13250
      }
1326
      else {
13270
        $output .= ' <colgroup' . drupal_attributes($attributes) . "
/>\n";
1328
      }
13290
    }
13300
  }
1331
1332
  // Format the table header:
1333232
  if (count($header)) {
1334232
    $ts = tablesort_init($header);
1335
    // HTML requires that the thead tag has tr tags in it follwed by tbody
1336
    // tags. Using ternary operator to check and see if we have any rows.
1337232
    $output .= (count($rows) ? ' <thead><tr>' : ' <tr>');
1338232
    foreach ($header as $cell) {
1339232
      $cell = tablesort_header($cell, $header, $ts);
1340232
      $output .= _theme_table_cell($cell, TRUE);
1341232
    }
1342
    // Using ternary operator to close the tags based on whether or not
there are rows
1343232
    $output .= (count($rows) ? " </tr></thead>\n" : "</tr>\n");
1344232
  }
1345
  else {
13460
    $ts = array();
1347
  }
1348
1349
  // Format the table rows:
1350232
  if (count($rows)) {
1351221
    $output .= "<tbody>\n";
1352221
    $flip = array('even' => 'odd', 'odd' => 'even');
1353221
    $class = 'even';
1354221
    foreach ($rows as $number => $row) {
1355221
      $attributes = array();
1356
1357
      // Check if we're dealing with a simple or complex row
1358221
      if (isset($row['data'])) {
135974
        foreach ($row as $key => $value) {
136074
          if ($key == 'data') {
136174
            $cells = $value;
136274
          }
1363
          else {
136474
            $attributes[$key] = $value;
1365
          }
136674
        }
136774
      }
1368
      else {
1369156
        $cells = $row;
1370
      }
1371221
      if (count($cells)) {
1372
        // Add odd/even class
1373221
        $class = $flip[$class];
1374221
        if (isset($attributes['class'])) {
137574
          $attributes['class'] .= ' ' . $class;
137674
        }
1377
        else {
1378156
          $attributes['class'] = $class;
1379
        }
1380
1381
        // Build row
1382221
        $output .= ' <tr' . drupal_attributes($attributes) . '>';
1383221
        $i = 0;
1384221
        foreach ($cells as $cell) {
1385221
          $cell = tablesort_cell($cell, $header, $ts, $i++);
1386221
          $output .= _theme_table_cell($cell);
1387221
        }
1388221
        $output .= " </tr>\n";
1389221
      }
1390221
    }
1391221
    $output .= "</tbody>\n";
1392221
  }
1393
1394232
  $output .= "</table>\n";
1395232
  return $output;
13960
}
1397
1398
/**
1399
 * Returns a header cell for tables that have a select all functionality.
1400
 */
14012027
function theme_table_select_header_cell() {
140217
  drupal_add_js('misc/tableselect.js');
1403
140417
  return array('class' => 'select-all');
14050
}
1406
1407
/**
1408
 * Return a themed sort icon.
1409
 *
1410
 * @param $style
1411
 *   Set to either asc or desc. This sets which icon to show.
1412
 * @return
1413
 *   A themed sort icon.
1414
 */
14152027
function theme_tablesort_indicator($style) {
141644
  if ($style == "asc") {
141740
    return theme('image', 'misc/arrow-asc.png', t('sort icon'), t('sort
ascending'));
14180
  }
1419
  else {
14204
    return theme('image', 'misc/arrow-desc.png', t('sort icon'), t('sort
descending'));
1421
  }
14220
}
1423
1424
/**
1425
 * Return a themed box.
1426
 *
1427
 * @param $title
1428
 *   The subject of the box.
1429
 * @param $content
1430
 *   The content of the box.
1431
 * @param $region
1432
 *   The region in which the box is displayed.
1433
 * @return
1434
 *   A string containing the box output.
1435
 */
14362027
function theme_box($title, $content, $region = 'main') {
14370
  $output = '<h2 class="title">' . $title . '</h2><div>' . $content .
'</div>';
14380
  return $output;
14390
}
1440
1441
/**
1442
 * Return a themed marker, useful for marking new or updated
1443
 * content.
1444
 *
1445
 * @param $type
1446
 *   Number representing the marker type to display
1447
 * @see MARK_NEW, MARK_UPDATED, MARK_READ
1448
 * @return
1449
 *   A string containing the marker.
1450
 */
14512027
function theme_mark($type = MARK_NEW) {
14528
  global $user;
14538
  if ($user->uid) {
14548
    if ($type == MARK_NEW) {
14555
      return ' <span class="marker">' . t('new') . '</span>';
14560
    }
14573
    else if ($type == MARK_UPDATED) {
14580
      return ' <span class="marker">' . t('updated') . '</span>';
14590
    }
14603
  }
14613
}
1462
1463
/**
1464
 * Return a themed list of items.
1465
 *
1466
 * @param $items
1467
 *   An array of items to be displayed in the list. If an item is a
string,
1468
 *   then it is used as is. If an item is an array, then the "data" element
of
1469
 *   the array is used as the contents of the list item. If an item is an
array
1470
 *   with a "children" element, those children are displayed in a nested
list.
1471
 *   All other elements are treated as attributes of the list item
element.
1472
 * @param $title
1473
 *   The title of the list.
1474
 * @param $attributes
1475
 *   The attributes applied to the list element.
1476
 * @param $type
1477
 *   The type of list to return (e.g. "ul", "ol")
1478
 * @return
1479
 *   A string containing the list output.
1480
 */
14812027
function theme_item_list($items = array(), $title = NULL, $type = 'ul',
$attributes = array()) {
1482362
  $output = '<div class="item-list">';
1483362
  if (isset($title)) {
14841
    $output .= '<h3>' . $title . '</h3>';
14851
  }
1486
1487362
  if (!empty($items)) {
1488360
    $output .= "<$type" . drupal_attributes($attributes) . '>';
1489360
    $num_items = count($items);
1490360
    foreach ($items as $i => $item) {
1491360
      $attributes = array();
1492360
      $children = array();
1493360
      if (is_array($item)) {
14946
        foreach ($item as $key => $value) {
14956
          if ($key == 'data') {
14966
            $data = $value;
14976
          }
14986
          elseif ($key == 'children') {
14990
            $children = $value;
15000
          }
1501
          else {
15026
            $attributes[$key] = $value;
1503
          }
15046
        }
15056
      }
1506
      else {
1507354
        $data = $item;
1508
      }
1509360
      if (count($children) > 0) {
15100
        $data .= theme_item_list($children, NULL, $type, $attributes); //
Render nested list
15110
      }
1512360
      if ($i == 0) {
1513360
        $attributes['class'] = empty($attributes['class']) ? 'first' :
($attributes['class'] . ' first');
1514360
      }
1515360
      if ($i == $num_items - 1) {
1516358
        $attributes['class'] = empty($attributes['class']) ? 'last' :
($attributes['class'] . ' last');
1517358
      }
1518360
      $output .= '<li' . drupal_attributes($attributes) . '>' . $data .
"</li>\n";
1519360
    }
1520360
    $output .= "</$type>";
1521360
  }
1522362
  $output .= '</div>';
1523362
  return $output;
15240
}
1525
1526
/**
1527
 * Returns code that emits the 'more help'-link.
1528
 */
15292027
function theme_more_help_link($url) {
1530184
  return '<div class="more-help-link">' . t('<a href="@link">More
help</a>', array('@link' => check_url($url))) . '</div>';
15310
}
1532
1533
/**
1534
 * Return code that emits an XML icon.
1535
 *
1536
 * For most use cases, this function has been superseded by
theme_feed_icon().
1537
 *
1538
 * @see theme_feed_icon()
1539
 * @param $url
1540
 *   The url of the feed.
1541
 */
15422027
function theme_xml_icon($url) {
15430
  if ($image = theme('image', 'misc/xml.png', t('XML feed'), t('XML
feed'))) {
15440
    return '<a href="' . check_url($url) . '" class="xml-icon">' . $image .
'</a>';
15450
  }
15460
}
1547
1548
/**
1549
 * Return code that emits an feed icon.
1550
 *
1551
 * @param $url
1552
 *   The url of the feed.
1553
 * @param $title
1554
 *   A descriptive title of the feed.
1555
  */
15562027
function theme_feed_icon($url, $title) {
155743
  if ($image = theme('image', 'misc/feed.png', t('Syndicate content'),
$title)) {
155843
    return '<a href="' . check_url($url) . '" class="feed-icon">' . $image
. '</a>';
15590
  }
15600
}
1561
1562
/**
1563
 * Returns code that emits the 'more' link used on blocks.
1564
 *
1565
 * @param $url
1566
 *   The url of the main page
1567
 * @param $title
1568
 *   A descriptive verb for the link, like 'Read more'
1569
 */
15702027
function theme_more_link($url, $title) {
1571146
  return '<div class="more-link">' . t('<a href="@link"
title="@title">more</a>', array('@link' => check_url($url), '@title' =>
$title)) . '</div>';
15720
}
1573
1574
/**
1575
 * Execute hook_footer() which is run at the end of the page right before
the
1576
 * close of the body tag.
1577
 *
1578
 * @param $main (optional)
1579
 *   Whether the current page is the front page of the site.
1580
 * @return
1581
 *   A string containing the results of the hook_footer() calls.
1582
 */
15832027
function theme_closure($main = 0) {
15841489
  $footer = module_invoke_all('footer', $main);
15851489
  return implode("\n", $footer) . drupal_get_js('footer');
15860
}
1587
1588
/**
1589
 * Return a set of blocks available for the current user.
1590
 *
1591
 * @param $region
1592
 *   Which set of blocks to retrieve.
1593
 * @return
1594
 *   A string containing the themed blocks for this region.
1595
 */
15962027
function theme_blocks($region) {
15971489
  $output = '';
1598
15991489
  if ($list = block_list($region)) {
16001489
    foreach ($list as $key => $block) {
1601
      // $key == <i>module</i>_<i>delta</i>
16021489
      $output .= theme('block', $block);
16031489
    }
16041489
  }
1605
1606
  // Add any content assigned to this region through drupal_set_content()
calls.
16071489
  $output .= drupal_get_content($region);
1608
16091489
  return $output;
16100
}
1611
1612
/**
1613
 * Format a username.
1614
 *
1615
 * @param $object
1616
 *   The user object to format, usually returned from user_load().
1617
 * @return
1618
 *   A string containing an HTML link to the user's page if the passed
object
1619
 *   suggests that this is a site user. Otherwise, only the username is
returned.
1620
 */
16212027
function theme_username($object) {
1622
1623285
  if ($object->uid && $object->name) {
1624
    // Shorten the name when it is too long or it will break many tables.
1625269
    if (drupal_strlen($object->name) > 20) {
1626116
      $name = drupal_substr($object->name, 0, 15) . '...';
1627116
    }
1628
    else {
1629191
      $name = $object->name;
1630
    }
1631
1632269
    if (user_access('access user profiles')) {
16331
      $output = l($name, 'user/' . $object->uid, array('attributes' =>
array('title' => t('View user profile.'))));
16341
    }
1635
    else {
1636268
      $output = check_plain($name);
1637
    }
1638269
  }
163934
  else if ($object->name) {
1640
    // Sometimes modules display content composed by people who are
1641
    // not registered members of the site (e.g. mailing list or news
1642
    // aggregator modules). This clause enables modules to display
1643
    // the true author of the content.
164418
    if (!empty($object->homepage)) {
16450
      $output = l($object->name, $object->homepage, array('attributes' =>
array('rel' => 'nofollow')));
16460
    }
1647
    else {
164818
      $output = check_plain($object->name);
1649
    }
1650
165118
    $output .= ' (' . t('not verified') . ')';
165218
  }
1653
  else {
165426
    $output = variable_get('anonymous', t('Anonymous'));
1655
  }
1656
1657285
  return $output;
16580
}
1659
1660
/**
1661
 * Return a themed progress bar.
1662
 *
1663
 * @param $percent
1664
 *   The percentage of the progress.
1665
 * @param $message
1666
 *   A string containing information to be displayed.
1667
 * @return
1668
 *   A themed HTML string representing the progress bar.
1669
 */
16702027
function theme_progress_bar($percent, $message) {
16710
  $output = '<div id="progress" class="progress">';
16720
  $output .= '<div class="bar"><div class="filled" style="width: ' .
$percent . '%"></div></div>';
16730
  $output .= '<div class="percentage">' . $percent . '%</div>';
16740
  $output .= '<div class="message">' . $message . '</div>';
16750
  $output .= '</div>';
1676
16770
  return $output;
16780
}
1679
1680
/**
1681
 * Create a standard indentation div. Used for drag and drop tables.
1682
 *
1683
 * @param $size
1684
 *   Optional. The number of indentations to create.
1685
 * @return
1686
 *   A string containing indentations.
1687
 */
16882027
function theme_indentation($size = 1) {
168932
  $output = '';
169032
  for ($n = 0; $n < $size; $n++) {
169130
    $output .= '<div class="indentation">&nbsp;</div>';
169230
  }
169332
  return $output;
16940
}
1695
1696
/**
1697
 * @} End of "defgroup themeable".
1698
 */
1699
17002027
function _theme_table_cell($cell, $header = FALSE) {
1701240
  $attributes = '';
1702
1703240
  if (is_array($cell)) {
1704209
    $data = isset($cell['data']) ? $cell['data'] : '';
1705209
    $header |= isset($cell['header']);
1706209
    unset($cell['data']);
1707209
    unset($cell['header']);
1708209
    $attributes = drupal_attributes($cell);
1709209
  }
1710
  else {
1711231
    $data = $cell;
1712
  }
1713
1714240
  if ($header) {
1715240
    $output = "<th$attributes>$data</th>";
1716240
  }
1717
  else {
1718221
    $output = "<td$attributes>$data</td>";
1719
  }
1720
1721240
  return $output;
17220
}
1723
1724
/**
1725
 * Adds a default set of helper variables for preprocess functions and
1726
 * templates. This comes in before any other preprocess function which
makes
1727
 * it possible to be used in default theme implementations (non-overriden
1728
 * theme functions).
1729
 */
17302027
function template_preprocess(&$variables, $hook) {
17311510
  global $user;
17321510
  static $count = array();
1733
1734
  // Track run count for each hook to provide zebra striping.
1735
  // See "template_preprocess_block()" which provides the same feature
specific to blocks.
17361510
  $count[$hook] = isset($count[$hook]) && is_int($count[$hook]) ?
$count[$hook] : 1;
17371510
  $variables['zebra'] = ($count[$hook] % 2) ? 'odd' : 'even';
17381510
  $variables['id'] = $count[$hook]++;
1739
1740
  // Tell all templates where they are located.
17411510
  $variables['directory'] = path_to_theme();
1742
1743
  // Set default variables that depend on the database.
17441510
  $variables['is_admin']            = FALSE;
17451510
  $variables['is_front']            = FALSE;
17461510
  $variables['logged_in']           = FALSE;
17471510
  if ($variables['db_is_active'] = db_is_active()  &&
!defined('MAINTENANCE_MODE')) {
1748
    // Check for administrators.
17491510
    if (user_access('access administration pages')) {
1750141
      $variables['is_admin'] = TRUE;
1751141
    }
1752
    // Flag front page status.
17531510
    $variables['is_front'] = drupal_is_front_page();
1754
    // Tell all templates by which kind of user they're viewed.
17551510
    $variables['logged_in'] = ($user->uid > 0);
1756
    // Provide user object to all templates
17571510
    $variables['user'] = $user;
17581510
  }
17591510
}
1760
1761
/**
1762
 * Process variables for page.tpl.php
1763
 *
1764
 * Most themes utilize their own copy of page.tpl.php. The default is
located
1765
 * inside "modules/system/page.tpl.php". Look in there for the full list
of
1766
 * variables.
1767
 *
1768
 * Uses the arg() function to generate a series of page template
suggestions
1769
 * based on the current path.
1770
 *
1771
 * Any changes to variables in this preprocessor should also be changed
inside
1772
 * template_preprocess_maintenance_page() to keep all them consistent.
1773
 *
1774
 * The $variables array contains the following arguments:
1775
 * - $content
1776
 * - $show_blocks
1777
 *
1778
 * @see page.tpl.php
1779
 */
17802027
function template_preprocess_page(&$variables) {
1781
  // Add favicon
17821489
  if (theme_get_setting('toggle_favicon')) {
17831489
    drupal_set_html_head('<link rel="shortcut icon" href="' .
check_url(theme_get_setting('favicon')) . '" type="image/x-icon" />');
17841489
  }
1785
17861489
  global $theme;
1787
  // Populate all block regions.
17881489
  $regions = system_region_list($theme);
1789
  // Load all region content assigned via blocks.
17901489
  foreach (array_keys($regions) as $region) {
1791
    // Prevent left and right regions from rendering blocks when
'show_blocks' == FALSE.
17921489
    if (!(!$variables['show_blocks'] && ($region == 'left' || $region ==
'right'))) {
17931489
      $blocks = theme('blocks', $region);
17941489
    }
1795
    else {
179612
      $blocks = '';
1797
    }
1798
    // Assign region to a region variable.
17991489
    isset($variables[$region]) ? $variables[$region] .= $blocks :
$variables[$region] = $blocks;
18001489
  }
1801
1802
  // Set up layout variable.
18031489
  $variables['layout'] = 'none';
18041489
  if (!empty($variables['left'])) {
18051263
    $variables['layout'] = 'left';
18061263
  }
18071489
  if (!empty($variables['right'])) {
1808166
    $variables['layout'] = ($variables['layout'] == 'left') ? 'both' :
'right';
1809166
  }
1810
1811
  // Set mission when viewing the frontpage.
18121489
  if (drupal_is_front_page()) {
1813204
    $mission = filter_xss_admin(theme_get_setting('mission'));
1814204
  }
1815
1816
  // Construct page title
18171489
  if (drupal_get_title()) {
18181285
    $head_title = array(strip_tags(drupal_get_title()),
variable_get('site_name', 'Drupal'));
18191285
  }
1820
  else {
1821204
    $head_title = array(variable_get('site_name', 'Drupal'));
1822204
    if (variable_get('site_slogan', '')) {
18230
      $head_title[] = variable_get('site_slogan', '');
18240
    }
1825
  }
18261489
  $variables['head_title']        = implode(' | ', $head_title);
18271489
  $variables['base_path']         = base_path();
18281489
  $variables['front_page']        = url();
18291489
  $variables['breadcrumb']        = theme('breadcrumb',
drupal_get_breadcrumb());
18301489
  $variables['feed_icons']        = drupal_get_feeds();
18311489
  $variables['footer_message']    =
filter_xss_admin(variable_get('site_footer', FALSE));
18321489
  $variables['head']              = drupal_get_html_head();
18331489
  $variables['help']              = theme('help');
18341489
  $variables['language']          = $GLOBALS['language'];
18351489
  $variables['language']->dir     = $GLOBALS['language']->direction ? 'rtl'
: 'ltr';
18361489
  $variables['logo']              = theme_get_setting('logo');
18371489
  $variables['messages']          = $variables['show_messages'] ?
theme('status_messages') : '';
18381489
  $variables['mission']           = isset($mission) ? $mission : '';
18391489
  $variables['main_menu']     = theme_get_setting('toggle_main_menu') ?
menu_main_menu() : array();
18401489
  $variables['secondary_menu']   =
theme_get_setting('toggle_secondary_menu') ? menu_secondary_menu() :
array();
18411489
  $variables['search_box']        = (theme_get_setting('toggle_search') ?
drupal_get_form('search_theme_form') : '');
18421489
  $variables['site_name']         = (theme_get_setting('toggle_name') ?
variable_get('site_name', 'Drupal') : '');
18431489
  $variables['site_slogan']       = (theme_get_setting('toggle_slogan') ?
variable_get('site_slogan', '') : '');
18441489
  $variables['css']               = drupal_add_css();
18451489
  $variables['styles']            = drupal_get_css();
18461489
  $variables['scripts']           = drupal_get_js();
18471489
  $variables['tabs']              = theme('menu_local_tasks');
18481489
  $variables['title']             = drupal_get_title();
1849
  // Closure should be filled last.
18501489
  $variables['closure']           = theme('closure');
1851
18521489
  if ($node = menu_get_object()) {
1853223
    $variables['node'] = $node;
1854223
  }
1855
1856
  // Compile a list of classes that are going to be applied to the body
element.
1857
  // This allows advanced theming based on context (home page, node of
certain type, etc.).
18581489
  $body_classes = array();
1859
  // Add a class that tells us whether we're on the front page or not.
18601489
  $body_classes[] = $variables['is_front'] ? 'front' : 'not-front';
1861
  // Add a class that tells us whether the page is viewed by an
authenticated user or not.
18621489
  $body_classes[] = $variables['logged_in'] ? 'logged-in' :
'not-logged-in';
1863
  // Add arg(0) to make it possible to theme the page depending on the
current page
1864
  // type (e.g. node, admin, user, etc.). To avoid illegal characters in
the class,
1865
  // we're removing everything disallowed. We are not using 'a-z' as that
might leave
1866
  // in certain international characters (e.g. German umlauts).
18671489
  $body_classes[] = preg_replace('![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s',
'', 'page-' . form_clean_id(drupal_strtolower(arg(0))));
1868
  // If on an individual node page, add the node type.
18691489
  if (isset($variables['node']) && $variables['node']->type) {
1870223
    $body_classes[] = 'node-type-' .
form_clean_id($variables['node']->type);
1871223
  }
1872
  // Add information about the number of sidebars.
18731489
  if ($variables['layout'] == 'both') {
1874164
    $body_classes[] = 'two-sidebars';
1875164
  }
18761325
  elseif ($variables['layout'] == 'none') {
1877225
    $body_classes[] = 'no-sidebars';
1878225
  }
1879
  else {
18801101
    $body_classes[] = 'one-sidebar sidebar-' . $variables['layout'];
1881
  }
1882
  // Implode with spaces.
18831489
  $variables['body_classes'] = implode(' ', $body_classes);
1884
1885
  // Build a list of suggested template files in order of specificity. One
1886
  // suggestion is made for every element of the current path, though
1887
  // numeric elements are not carried to subsequent suggestions. For
example,
1888
  // http://www.example.com/node/1/edit would result in the following
1889
  // suggestions:
1890
  //
1891
  // page-node-edit.tpl.php
1892
  // page-node-1.tpl.php
1893
  // page-node.tpl.php
1894
  // page.tpl.php
18951489
  $i = 0;
18961489
  $suggestion = 'page';
18971489
  $suggestions = array();
18981489
  while ($arg = arg($i++)) {
18991489
    $suggestions[] = $suggestion . '-' . $arg;
19001489
    if (!is_numeric($arg)) {
19011489
      $suggestion .= '-' . $arg;
19021489
    }
19031489
  }
19041489
  if (drupal_is_front_page()) {
1905204
    $suggestions[] = 'page-front';
1906204
  }
1907
19081489
  if ($suggestions) {
19091489
    $variables['template_files'] = $suggestions;
19101489
  }
19111489
}
1912
1913
/**
1914
 * Process variables for node.tpl.php
1915
 *
1916
 * Most themes utilize their own copy of node.tpl.php. The default is
located
1917
 * inside "modules/node/node.tpl.php". Look in there for the full list of
1918
 * variables.
1919
 *
1920
 * The $variables array contains the following arguments:
1921
 * - $node
1922
 * - $teaser
1923
 * - $page
1924
 *
1925
 * @see node.tpl.php
1926
 */
19272027
function template_preprocess_node(&$variables) {
1928233
  $node = $variables['node'];
1929233
  if (module_exists('taxonomy')) {
1930233
    $variables['taxonomy'] = taxonomy_link('taxonomy terms', $node);
1931233
  }
1932
  else {
19330
    $variables['taxonomy'] = array();
1934
  }
1935
1936233
  if ($variables['teaser'] && $node->teaser) {
193723
    $variables['content'] = $node->teaser;
193823
  }
1939210
  elseif (isset($node->body)) {
1940206
    $variables['content'] = $node->body;
1941206
  }
1942
  else {
19435
    $variables['content'] = '';
1944
  }
1945
1946233
  $variables['date']      = format_date($node->created);
1947233
  $variables['links']     = !empty($node->links) ? theme('links',
$node->links, array('class' => 'links inline')) : '';
1948233
  $variables['name']      = theme('username', $node);
1949233
  $variables['node_url']  = url('node/' . $node->nid);
1950233
  $variables['terms']     = theme('links', $variables['taxonomy'],
array('class' => 'links inline'));
1951233
  $variables['title']     = check_plain($node->title);
1952
1953
  // Flatten the node object's member fields.
1954233
  $variables = array_merge((array)$node, $variables);
1955
1956
  // Display info only on certain node types.
1957233
  if (theme_get_setting('toggle_node_info_' . $node->type)) {
1958170
    $variables['submitted'] = theme('node_submitted', $node);
1959170
    $variables['picture'] = theme_get_setting('toggle_node_user_picture') ?
theme('user_picture', $node) : '';
1960170
  }
1961
  else {
196263
    $variables['submitted'] = '';
196363
    $variables['picture'] = '';
1964
  }
1965
  // Clean up name so there are no underscores.
1966233
  $variables['template_files'][] = 'node-' . str_replace('_', '-',
$node->type);
1967233
  $variables['template_files'][] = 'node-' . $node->nid;
1968233
}
1969
1970
/**
1971
 * Process variables for block.tpl.php
1972
 *
1973
 * Prepare the values passed to the theme_block function to be passed
1974
 * into a pluggable template engine. Uses block properties to generate a
1975
 * series of template file suggestions. If none are found, the default
1976
 * block.tpl.php is used.
1977
 *
1978
 * Most themes utilize their own copy of block.tpl.php. The default is
located
1979
 * inside "modules/system/block.tpl.php". Look in there for the full list
of
1980
 * variables.
1981
 *
1982
 * The $variables array contains the following arguments:
1983
 * - $block
1984
 *
1985
 * @see block.tpl.php
1986
 */
19872027
function template_preprocess_block(&$variables) {
19881489
  static $block_counter = array();
1989
  // All blocks get an independent counter for each region.
19901489
  if (!isset($block_counter[$variables['block']->region])) {
19911489
    $block_counter[$variables['block']->region] = 1;
19921489
  }
1993
  // Same with zebra striping.
19941489
  $variables['block_zebra'] = ($block_counter[$variables['block']->region]
% 2) ? 'odd' : 'even';
19951489
  $variables['block_id'] = $block_counter[$variables['block']->region]++;
1996
19971489
  $variables['template_files'][] = 'block-' . $variables['block']->region;
19981489
  $variables['template_files'][] = 'block-' . $variables['block']->module;
19991489
  $variables['template_files'][] = 'block-' . $variables['block']->module .
'-' . $variables['block']->delta;
20001489
}
2001
20022027