Code coverage for /20081101/includes/theme.inc

Line #Times calledCode
1
<?php
2
// $Id: theme.inc,v 1.446 2008/10/26 18:06:38 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/171179">Theme guide</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
 */
252366
define('MARK_READ', 0);
26
27
/**
28
 * Mark content as being new.
29
 */
302366
define('MARK_NEW', 1);
31
32
/**
33
 * Mark content as being updated.
34
 */
352366
define('MARK_UPDATED', 2);
36
37
/**
38
 * @} End of "Content markers".
39
 */
40
41
/**
42
 * Initialize the theme system by loading the theme.
43
 */
442366
function init_theme() {
452158
  global $theme, $user, $custom_theme, $theme_key;
46
47
  // If $theme is already set, assume the others are set, too, and do
nothing
482158
  if (isset($theme)) {
491000
    return;
50
  }
51
522158
  drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
532158
  $themes = list_themes();
54
55
  // Only select the user selected theme if it is available in the
56
  // list of enabled themes.
572158
  $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.
612158
  $theme = $custom_theme && $themes[$custom_theme] ? $custom_theme :
$theme;
62
63
  // Store the identifier for retrieving theme settings with.
642158
  $theme_key = $theme;
65
66
  // Find all our ancestor themes and put them in an array.
672158
  $base_theme = array();
682158
  $ancestor = $theme;
692158
  while ($ancestor && isset($themes[$ancestor]->base_theme)) {
70
    $base_theme[] = $new_base_theme =
$themes[$themes[$ancestor]->base_theme];
71
    $ancestor = $themes[$ancestor]->base_theme;
72
  }
732158
  _init_theme($themes[$theme], array_reverse($base_theme));
742158
}
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
 */
1012366
function _init_theme($theme, $base_theme = array(), $registry_callback =
'_theme_load_registry') {
1022158
  global $theme_info, $base_theme_info, $theme_engine, $theme_path;
1032158
  $theme_info = $theme;
1042158
  $base_theme_info = $base_theme;
105
1062158
  $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.
1112158
  $final_stylesheets = array();
112
113
  // Grab stylesheets from base theme
1142158
  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.
1252158
  if (!empty($theme->stylesheets)) {
1262158
    foreach ($theme->stylesheets as $media => $stylesheets) {
1272158
      foreach ($stylesheets as $name => $stylesheet) {
1282158
        $final_stylesheets[$media][$name] = $stylesheet;
1292158
      }
1302158
    }
1312158
  }
132
133
  // And now add the stylesheets properly
1342158
  foreach ($final_stylesheets as $media => $stylesheets) {
1352158
    foreach ($stylesheets as $stylesheet) {
1362158
      drupal_add_css($stylesheet, array('type' => 'theme', 'media' =>
$media));
1372158
    }
1382158
  }
139
140
  // Do basically the same as the above for scripts
1412158
  $final_scripts = array();
142
143
  // Grab scripts from base theme
1442158
  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.
1532158
  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.
1602158
  foreach ($final_scripts as $script) {
1610
    drupal_add_js($script, 'theme');
1620
  }
163
1642158
  $theme_engine = NULL;
165
166
  // Initialize the theme.
1672158
  if (isset($theme->engine)) {
168
    // Include the engine.
1692158
    include_once DRUPAL_ROOT . '/' . $theme->owner;
170
1712158
    $theme_engine = $theme->engine;
1722158
    if (function_exists($theme_engine . '_init')) {
1732158
      foreach ($base_theme as $base) {
1740
        call_user_func($theme_engine . '_init', $base);
1750
      }
1762158
      call_user_func($theme_engine . '_init', $theme);
1772158
    }
1782158
  }
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 DRUPAL_ROOT . '/' . $base->owner;
1850
      }
1860
    }
187
    // and our theme gets one too.
1880
    if (!empty($theme->owner)) {
1890
      include_once DRUPAL_ROOT . '/' . $theme->owner;
1900
    }
191
  }
192
1932158
  if (drupal_function_exists($registry_callback)) {
1942158
    $registry_callback($theme, $base_theme, $theme_engine);
1952158
  }
1962158
}
197
198
/**
199
 * Get the theme registry.
200
 * @return
201
 *   The theme registry array if it has been stored in memory, NULL
otherwise.
202
 */
2032366
function theme_get_registry() {
2042150
  return _theme_set_registry();
2050
}
206
207
/**
208
 * Store the theme registry in memory.
209
 * @param $registry
210
 *   A registry array as returned by _theme_build_registry()
211
 * @return
212
 *   The theme registry array stored in memory
213
 */
2142366
function _theme_set_registry($registry = NULL) {
2152158
  static $theme_registry = NULL;
216
2172158
  if (isset($registry)) {
2182158
    $theme_registry = $registry;
2192158
  }
220
2212158
  return $theme_registry;
2220
}
223
224
/**
225
 * Get the theme_registry cache from the database; if it doesn't exist,
build
226
 * it.
227
 *
228
 * @param $theme
229
 *   The loaded $theme object.
230
 * @param $base_theme
231
 *   An array of loaded $theme objects representing the ancestor themes in
232
 *   oldest first order.
233
 * @param theme_engine
234
 *   The name of the theme engine.
235
 */
2362366
function _theme_load_registry($theme, $base_theme = NULL, $theme_engine =
NULL) {
237
  // Check the theme registry cache; if it exists, use it.
2382158
  $cache = cache_get("theme_registry:$theme->name", 'cache');
2392158
  if (isset($cache->data)) {
2401980
    $registry = $cache->data;
2411980
  }
242
  else {
243
    // If not, build one and cache it.
244178
    $registry = _theme_build_registry($theme, $base_theme, $theme_engine);
245178
    _theme_save_registry($theme, $registry);
246
  }
2472158
  _theme_set_registry($registry);
2482158
}
249
250
/**
251
 * Write the theme_registry cache into the database.
252
 */
2532366
function _theme_save_registry($theme, $registry) {
254178
  cache_set("theme_registry:$theme->name", $registry);
255178
}
256
257
/**
258
 * Force the system to rebuild the theme registry; this should be called
259
 * when modules are added to the system, or when a dynamic system needs
260
 * to add more theme hooks.
261
 */
2622366
function drupal_theme_rebuild() {
26326
  cache_clear_all('theme_registry', 'cache', TRUE);
26426
}
265
266
/**
267
 * Process a single invocation of the theme hook. $type will be one
268
 * of 'module', 'theme_engine', 'base_theme_engine', 'theme', or
'base_theme'
269
 * and it tells us some important information.
270
 *
271
 * Because $cache is a reference, the cache will be continually
272
 * expanded upon; new entries will replace old entries in the
273
 * array_merge, but we are careful to ensure some data is carried
274
 * forward, such as the arguments a theme hook needs.
275
 *
276
 * An override flag can be set for preprocess functions. When detected the
277
 * cached preprocessors for the hook will not be merged with the newly set.
278
 * This can be useful to themes and theme engines by giving them more
control
279
 * over how and when the preprocess functions are run.
280
 */
2812366
function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
282178
  $result = array();
283178
  $function = $name . '_theme';
284178
  if (function_exists($function)) {
285178
    $result = $function($cache, $type, $theme, $path);
286
287178
    foreach ($result as $hook => $info) {
288178
      $result[$hook]['type'] = $type;
289178
      $result[$hook]['theme path'] = $path;
290
      // if function and file are left out, default to standard naming
291
      // conventions.
292178
      if (!isset($info['template']) && !isset($info['function'])) {
293178
        $result[$hook]['function'] = ($type == 'module' ? 'theme_' : $name
. '_') . $hook;
294178
      }
295
      // If a path is set in the info, use what was set. Otherwise use the
296
      // default path. This is mostly so system.module can declare theme
297
      // functions on behalf of core .include files.
298
      // All files are included to be safe. Conditionally included
299
      // files can prevent them from getting registered.
300178
      if (isset($info['file']) && !isset($info['path'])) {
301178
        $result[$hook]['file'] = $path . '/' . $info['file'];
302178
        include_once DRUPAL_ROOT . '/' . $result[$hook]['file'];
303178
      }
304178
      elseif (isset($info['file']) && isset($info['path'])) {
3050
        include_once DRUPAL_ROOT . '/' . $info['path'] . '/' .
$info['file'];
3060
      }
307
308178
      if (isset($info['template']) && !isset($info['path'])) {
309178
        $result[$hook]['template'] = $path . '/' . $info['template'];
310178
      }
311
      // If 'arguments' have been defined previously, carry them forward.
312
      // This should happen if a theme overrides a Drupal defined theme
313
      // function, for example.
314178
      if (!isset($info['arguments']) && isset($cache[$hook])) {
315178
        $result[$hook]['arguments'] = $cache[$hook]['arguments'];
316178
      }
317
      // Likewise with theme paths. These are used for template naming
suggestions.
318
      // Theme implementations can occur in multiple paths. Suggestions
should follow.
319178
      if (!isset($info['theme paths']) && isset($cache[$hook])) {
320178
        $result[$hook]['theme paths'] = $cache[$hook]['theme paths'];
321178
      }
322
      // Check for sub-directories.
323178
      $result[$hook]['theme paths'][] = isset($info['path']) ?
$info['path'] : $path;
324
325
      // Check for default _preprocess_ functions. Ensure arrayness.
326178
      if (!isset($info['preprocess functions']) ||
!is_array($info['preprocess functions'])) {
327178
        $info['preprocess functions'] = array();
328178
        $prefixes = array();
329178
        if ($type == 'module') {
330
          // Default preprocessor prefix.
331178
          $prefixes[] = 'template';
332
          // Add all modules so they can intervene with their own
preprocessors. This allows them
333
          // to provide preprocess functions even if they are not the owner
of the current hook.
334178
          $prefixes += module_list();
335178
        }
336178
        elseif ($type == 'theme_engine' || $type == 'base_theme_engine') {
337
          // Theme engines get an extra set that come before the normally
named preprocessors.
338178
          $prefixes[] = $name . '_engine';
339
          // The theme engine also registers on behalf of the theme. The
theme or engine name can be used.
340178
          $prefixes[] = $name;
341178
          $prefixes[] = $theme;
342178
        }
343
        else {
344
          // This applies when the theme manually registers their own
preprocessors.
3450
          $prefixes[] = $name;
346
        }
347
348178
        foreach ($prefixes as $prefix) {
349178
          if (function_exists($prefix . '_preprocess')) {
350178
            $info['preprocess functions'][] = $prefix . '_preprocess';
351178
          }
352178
          if (function_exists($prefix . '_preprocess_' . $hook)) {
353178
            $info['preprocess functions'][] = $prefix . '_preprocess_' .
$hook;
354178
          }
355178
        }
356178
      }
357
      // Check for the override flag and prevent the cached preprocess
functions from being used.
358
      // This allows themes or theme engines to remove preprocessors set
earlier in the registry build.
359178
      if (!empty($info['override preprocess functions'])) {
360
        // Flag not needed inside the registry.
3610
        unset($result[$hook]['override preprocess functions']);
3620
      }
363178
      elseif (isset($cache[$hook]['preprocess functions']) &&
is_array($cache[$hook]['preprocess functions'])) {
364178
        $info['preprocess functions'] =
array_merge($cache[$hook]['preprocess functions'], $info['preprocess
functions']);
365178
      }
366178
      $result[$hook]['preprocess functions'] = $info['preprocess
functions'];
367178
    }
368
369
    // Merge the newly created theme hooks into the existing cache.
370178
    $cache = array_merge($cache, $result);
371178
  }
372
373
  // Let themes have preprocess functions even if they didn't register a
template.
374178
  if ($type == 'theme' || $type == 'base_theme') {
375178
    foreach ($cache as $hook => $info) {
376
      // Check only if it's a template and not registered by the theme or
engine
377178
      if (!empty($info['template']) && empty($result[$hook])) {
378178
        if (!isset($info['preprocess functions'])) {
3790
          $cache[$hook]['preprocess functions'] = array();
3800
        }
381178
        if (function_exists($name . '_preprocess')) {
3820
          $cache[$hook]['preprocess functions'][] = $name . '_preprocess';
3830
        }
384178
        if (function_exists($name . '_preprocess_' . $hook)) {
385177
          $cache[$hook]['preprocess functions'][] = $name . '_preprocess_'
. $hook;
386177
        }
387
        // Ensure uniqueness.
388178
        $cache[$hook]['preprocess functions'] =
array_unique($cache[$hook]['preprocess functions']);
389178
      }
390178
    }
391178
  }
392178
}
393
394
/**
395
 * Rebuild the hook theme_registry cache.
396
 *
397
 * @param $theme
398
 *   The loaded $theme object.
399
 * @param $base_theme
400
 *   An array of loaded $theme objects representing the ancestor themes in
401
 *   oldest first order.
402
 * @param theme_engine
403
 *   The name of the theme engine.
404
 */
4052366
function _theme_build_registry($theme, $base_theme, $theme_engine) {
406178
  $cache = array();
407
  // First, process the theme hooks advertised by modules. This will
408
  // serve as the basic registry.
409178
  foreach (module_implements('theme') as $module) {
410178
    _theme_process_registry($cache, $module, 'module', $module,
drupal_get_path('module', $module));
411178
  }
412
413
  // Process each base theme.
414178
  foreach ($base_theme as $base) {
415
    // If the base theme uses a theme engine, process its hooks.
4160
    $base_path = dirname($base->filename);
4170
    if ($theme_engine) {
4180
      _theme_process_registry($cache, $theme_engine, 'base_theme_engine',
$base->name, $base_path);
4190
    }
4200
    _theme_process_registry($cache, $base->name, 'base_theme', $base->name,
$base_path);
4210
  }
422
423
  // And then the same thing, but for the theme.
424178
  if ($theme_engine) {
425178
    _theme_process_registry($cache, $theme_engine, 'theme_engine',
$theme->name, dirname($theme->filename));
426178
  }
427
428
  // Finally, hooks provided by the theme itself.
429178
  _theme_process_registry($cache, $theme->name, 'theme', $theme->name,
dirname($theme->filename));
430
431
  // Let modules alter the registry
432178
  drupal_alter('theme_registry', $cache);
433178
  return $cache;
4340
}
435
436
/**
437
 * Provides a list of currently available themes.
438
 *
439
 * If the database is active then it will be retrieved from the database.
440
 * Otherwise it will retrieve a new list.
441
 *
442
 * @param $refresh
443
 *   Whether to reload the list of themes from the database.
444
 * @return
445
 *   An array of the currently available themes.
446
 */
4472366
function list_themes($refresh = FALSE) {
4482159
  static $list = array();
449
4502159
  if ($refresh) {
4511
    $list = array();
4521
  }
453
4542159
  if (empty($list)) {
4552159
    $list = array();
4562159
    $themes = array();
457
    // Extract from the database only when it is available.
458
    // Also check that the site is not in the middle of an install or
update.
4592159
    if (db_is_active() && !defined('MAINTENANCE_MODE')) {
4602159
      $result = db_query("SELECT * FROM {system} WHERE type = '%s'",
'theme');
4612159
      while ($theme = db_fetch_object($result)) {
4622159
        if (file_exists($theme->filename)) {
4632159
          $theme->info = unserialize($theme->info);
4642159
          $themes[] = $theme;
4652159
        }
4662159
      }
4672159
    }
468
    else {
469
      // Scan the installation when the database should not be read.
4700
      $themes = _system_theme_data();
471
    }
472
4732159
    foreach ($themes as $theme) {
4742159
      foreach ($theme->info['stylesheets'] as $media => $stylesheets) {
4752159
        foreach ($stylesheets as $stylesheet => $path) {
4762159
          $theme->stylesheets[$media][$stylesheet] = $path;
4772159
        }
4782159
      }
4792159
      foreach ($theme->info['scripts'] as $script => $path) {
4802159
        if (file_exists($path)) {
4810
          $theme->scripts[$script] = $path;
4820
        }
4832159
      }
4842159
      if (isset($theme->info['engine'])) {
4852159
        $theme->engine = $theme->info['engine'];
4862159
      }
4872159
      if (isset($theme->info['base theme'])) {
4882159
        $theme->base_theme = $theme->info['base theme'];
4892159
      }
490
      // Status is normally retrieved from the database. Add zero values
when
491
      // read from the installation directory to prevent notices.
4922159
      if (!isset($theme->status)) {
4930
        $theme->status = 0;
4940
      }
4952159
      $list[$theme->name] = $theme;
4962159
    }
4972159
  }
498
4992159
  return $list;
5000
}
501
502
/**
503
 * Generate the themed output.
504
 *
505
 * All requests for theme hooks must go through this function. It examines
506
 * the request and routes it to the appropriate theme function. The theme
507
 * registry is checked to determine which implementation to use, which may
508
 * be a function or a template.
509
 *
510
 * If the implementation is a function, it is executed and its return value
511
 * passed along.
512
 *
513
 * If the implementation is a template, the arguments are converted to a
514
 * $variables array. This array is then modified by the module implementing
515
 * the hook, theme engine (if applicable) and the theme. The following
516
 * functions may be used to modify the $variables array. They are processed
in
517
 * this order when available:
518
 *
519
 * - template_preprocess(&$variables)
520
 *   This sets a default set of variables for all template implementations.
521
 *
522
 * - template_preprocess_HOOK(&$variables)
523
 *   This is the first preprocessor called specific to the hook; it should
be
524
 *   implemented by the module that registers it.
525
 *
526
 * - MODULE_preprocess(&$variables)
527
 *   This will be called for all templates; it should only be used if there
528
 *   is a real need. It's purpose is similar to template_preprocess().
529
 *
530
 * - MODULE_preprocess_HOOK(&$variables)
531
 *   This is for modules that want to alter or provide extra variables for
532
 *   theming hooks not registered to itself. For example, if a module named
533
 *   "foo" wanted to alter the $submitted variable for the hook "node" a
534
 *   preprocess function of foo_preprocess_node() can be created to
intercept
535
 *   and alter the variable.
536
 *
537
 * - ENGINE_engine_preprocess(&$variables)
538
 *   This function should only be implemented by theme engines and exists
539
 *   so that it can set necessary variables for all hooks.
540
 *
541
 * - ENGINE_engine_preprocess_HOOK(&$variables)
542
 *   This is the same as the previous function, but it is called for a
single
543
 *   theming hook.
544
 *
545
 * - ENGINE_preprocess(&$variables)
546
 *   This is meant to be used by themes that utilize a theme engine. It is
547
 *   provided so that the preprocessor is not locked into a specific theme.
548
 *   This makes it easy to share and transport code but theme authors must
be
549
 *   careful to prevent fatal re-declaration errors when using sub-themes
that
550
 *   have their own preprocessor named exactly the same as its base theme.
In
551
 *   the default theme engine (PHPTemplate), sub-themes will load their own
552
 *   template.php file in addition to the one used for its parent theme.
This
553
 *   increases the risk for these errors. A good practice is to use the
engine
554
 *   name for the base theme and the theme name for the sub-themes to
minimize
555
 *   this possibility.
556
 *
557
 * - ENGINE_preprocess_HOOK(&$variables)
558
 *   The same applies from the previous function, but it is called for a
559
 *   specific hook.
560
 *
561
 * - THEME_preprocess(&$variables)
562
 *   These functions are based upon the raw theme; they should primarily be
563
 *   used by themes that do not use an engine or by sub-themes. It serves
the
564
 *   same purpose as ENGINE_preprocess().
565
 *
566
 * - THEME_preprocess_HOOK(&$variables)
567
 *   The same applies from the previous function, but it is called for a
568
 *   specific hook.
569
 *
570
 * There are two special variables that these hooks can set:
571
 *   'template_file' and 'template_files'. These will be merged together
572
 *   to form a list of 'suggested' alternate template files to use, in
573
 *   reverse order of priority. template_file will always be a higher
574
 *   priority than items in template_files. theme() will then look for
these
575
 *   files, one at a time, and use the first one
576
 *   that exists.
577
 * @param $hook
578
 *   The name of the theme function to call. May be an array, in which
579
 *   case the first hook that actually has an implementation registered
580
 *   will be used. This can be used to choose 'fallback' theme
implementations,
581
 *   so that if the specific theme hook isn't implemented anywhere, a more
582
 *   generic one will be used. This can allow themes to create specific
theme
583
 *   implementations for named objects.
584
 * @param ...
585
 *   Additional arguments to pass along to the theme function.
586
 * @return
587
 *   An HTML string that generates the themed output.
588
 */
5892366
function theme() {
5902150
  $args = func_get_args();
5912150
  $hook = array_shift($args);
592
5932150
  static $hooks = NULL;
5942150
  if (!isset($hooks)) {
5952150
    init_theme();
5962150
    $hooks = theme_get_registry();
5972150
  }
598
5992150
  if (is_array($hook)) {
60092
    foreach ($hook as $candidate) {
60192
      if (isset($hooks[$candidate])) {
60292
        break;
6030
      }
60492
    }
60592
    $hook = $candidate;
60692
  }
607
6082150
  if (!isset($hooks[$hook])) {
609476
    return;
6100
  }
611
6122150
  $info = $hooks[$hook];
6132150
  global $theme_path;
6142150
  $temp = $theme_path;
615
  // point path_to_theme() to the currently used theme path:
6162150
  $theme_path = $info['theme path'];
617
618
  // Include a file if the theme function or preprocess function is held
elsewhere.
6192150
  if (!empty($info['file'])) {
620584
    $include_file = $info['file'];
621584
    if (isset($info['path'])) {
6220
      $include_file = $info['path'] . '/' . $include_file;
6230
    }
624584
    include_once DRUPAL_ROOT . '/' . $include_file;
625584
  }
6262150
  if (isset($info['function'])) {
627
    // The theme call is a function.
6282150
    $output = call_user_func_array($info['function'], $args);
6292150
  }
630
  else {
631
    // The theme call is a template.
632
    $variables = array(
6331765
      'template_files' => array()
6341765
    );
6351765
    if (!empty($info['arguments'])) {
6361765
      $count = 0;
6371765
      foreach ($info['arguments'] as $name => $default) {
6381765
        $variables[$name] = isset($args[$count]) ? $args[$count] :
$default;
6391765
        $count++;
6401765
      }
6411765
    }
642
643
    // default render function and extension.
6441765
    $render_function = 'theme_render_template';
6451765
    $extension = '.tpl.php';
646
647
    // Run through the theme engine variables, if necessary
6481765
    global $theme_engine;
6491765
    if (isset($theme_engine)) {
650
      // If theme or theme engine is implementing this, it may have
651
      // a different extension and a different renderer.
6521765
      if ($info['type'] != 'module') {
6531757
        if (function_exists($theme_engine . '_render_template')) {
6540
          $render_function = $theme_engine . '_render_template';
6550
        }
6561757
        $extension_function = $theme_engine . '_extension';
6571757
        if (function_exists($extension_function)) {
6580
          $extension = $extension_function();
6590
        }
6601757
      }
6611765
    }
662
6631765
    if (isset($info['preprocess functions']) && is_array($info['preprocess
functions'])) {
664
      // This construct ensures that we can keep a reference through
665
      // call_user_func_array.
6661765
      $args = array(&$variables, $hook);
6671765
      foreach ($info['preprocess functions'] as $preprocess_function) {
6681765
        if (drupal_function_exists($preprocess_function)) {
6691765
          call_user_func_array($preprocess_function, $args);
6701765
        }
6711765
      }
6721765
    }
673
674
    // Get suggestions for alternate templates out of the variables
675
    // that were set. This lets us dynamically choose a template
676
    // from a list. The order is FILO, so this array is ordered from
677
    // least appropriate first to most appropriate last.
6781765
    $suggestions = array();
679
6801765
    if (isset($variables['template_files'])) {
6811765
      $suggestions = $variables['template_files'];
6821765
    }
6831765
    if (isset($variables['template_file'])) {
6840
      $suggestions[] = $variables['template_file'];
6850
    }
686
6871765
    if ($suggestions) {
6881755
      $template_file = drupal_discover_template($info['theme paths'],
$suggestions, $extension);
6891755
    }
690
6911765
    if (empty($template_file)) {
6921765
      $template_file = $info['template'] . $extension;
6931765
      if (isset($info['path'])) {
6941757
        $template_file = $info['path'] . '/' . $template_file;
6951757
      }
6961765
    }
6971765
    $output = $render_function($template_file, $variables);
698
  }
699
  // restore path_to_theme()
7002150
  $theme_path = $temp;
7012150
  return $output;
7020
}
703
704
/**
705
 * Choose which template file to actually render. These are all suggested
706
 * templates from themes and modules. Theming implementations can occur on
707
 * multiple levels. All paths are checked to account for this.
708
 */
7092366
function drupal_discover_template($paths, $suggestions, $extension =
'.tpl.php') {
7101755
  global $theme_engine;
711
712
  // Loop through all paths and suggestions in FIFO order.
7131755
  $suggestions = array_reverse($suggestions);
7141755
  $paths = array_reverse($paths);
7151755
  foreach ($suggestions as $suggestion) {
7161755
    if (!empty($suggestion)) {
7171755
      foreach ($paths as $path) {
7181755
        if (file_exists($file = $path . '/' . $suggestion . $extension)) {
7190
          return $file;
7200
        }
7211755
      }
7221755
    }
7231755
  }
7241755
}
725
726
/**
727
 * Return the path to the current themed element.
728
 *
729
 * It can point to the active theme or the module handling a themed
implementation.
730
 * For example, when invoked within the scope of a theming call it will
depend
731
 * on where the theming function is handled. If implemented from a module,
it
732
 * will point to the module. If implemented from the active theme, it will
point
733
 * to the active theme. When called outside the scope of a theming call, it
will
734
 * always point to the active theme.
735
 */
7362366
function path_to_theme() {
7371765
  global $theme_path;
738
7391765
  if (!isset($theme_path)) {
7400
    init_theme();
7410
  }
742
7431765
  return $theme_path;
7440
}
745
746
/**
747
 * Find overridden theme functions. Called by themes and/or theme engines
to
748
 * easily discover theme functions.
749
 *
750
 * @param $cache
751
 *   The existing cache of theme hooks to test against.
752
 * @param $prefixes
753
 *   An array of prefixes to test, in reverse order of importance.
754
 *
755
 * @return $templates
756
 *   The functions found, suitable for returning from hook_theme;
757
 */
7582366
function drupal_find_theme_functions($cache, $prefixes) {
759178
  $templates = array();
760178
  $functions = get_defined_functions();
761
762178
  foreach ($cache as $hook => $info) {
763178
    foreach ($prefixes as $prefix) {
764178
      if (!empty($info['pattern'])) {
7650
        $matches = preg_grep('/^' . $prefix . '_' . $info['pattern'] . '/',
$functions['user']);
7660
        if ($matches) {
7670
          foreach ($matches as $match) {
7680
            $new_hook = str_replace($prefix . '_', '', $match);
7690
            $templates[$new_hook] = array(
7700
              'function' => $match,
7710
              'arguments' => $info['arguments'],
772
            );
7730
          }
7740
        }
7750
      }
776178
      if (function_exists($prefix . '_' . $hook)) {
777177
        $templates[$hook] = array(
778177
          'function' => $prefix . '_' . $hook,
779
        );
780177
      }
781178
    }
782178
  }
783
784178
  return $templates;
7850
}
786
787
/**
788
 * Find overridden theme templates. Called by themes and/or theme engines
to
789
 * easily discover templates.
790
 *
791
 * @param $cache
792
 *   The existing cache of theme hooks to test against.
793
 * @param $extension
794
 *   The extension that these templates will have.
795
 * @param $path
796
 *   The path to search.
797
 */
7982366
function drupal_find_theme_templates($cache, $extension, $path) {
799178
  $templates = array();
800
801
  // Collect paths to all sub-themes grouped by base themes. These will be
802
  // used for filtering. This allows base themes to have sub-themes in its
803
  // folder hierarchy without affecting the base themes template discovery.
804178
  $theme_paths = array();
805178
  foreach (list_themes() as $theme_info) {
806178
    if (!empty($theme_info->base_theme)) {
807178
      $theme_paths[$theme_info->base_theme][$theme_info->name] =
dirname($theme_info->filename);
808178
    }
809178
  }
810178
  foreach ($theme_paths as $basetheme => $subthemes) {
811178
    foreach ($subthemes as $subtheme => $subtheme_path) {
812178
      if (isset($theme_paths[$subtheme])) {
8130
        $theme_paths[$basetheme] = array_merge($theme_paths[$basetheme],
$theme_paths[$subtheme]);
8140
      }
815178
    }
816178
  }
817178
  global $theme;
818178
  $subtheme_paths = isset($theme_paths[$theme]) ? $theme_paths[$theme] :
array();
819
820
  // Escape the periods in the extension.
821178
  $regex = '/'. str_replace('.', '\.', $extension) . '$/';
822
  // Because drupal_system_listing works the way it does, we check for real
823
  // templates separately from checking for patterns.
824178
  $files = drupal_system_listing($regex, $path, 'name', 0);
825178
  foreach ($files as $template => $file) {
826
    // Ignore sub-theme templates for the current theme.
827178
    if (strpos($file->filename, str_replace($subtheme_paths, '',
$file->filename)) !== 0) {
8280
      continue;
8290
    }
830
    // Chop off the remaining extensions if there are any. $template
already
831
    // has the rightmost extension removed, but there might still be more,
832
    // such as with .tpl.php, which still has .tpl in $template at this
point.
833178
    if (($pos = strpos($template, '.')) !== FALSE) {
834178
      $template = substr($template, 0, $pos);
835178
    }
836
    // Transform - in filenames to _ to match function naming scheme
837
    // for the purposes of searching.
838178
    $hook = strtr($template, '-', '_');
839178
    if (isset($cache[$hook])) {
840178
      $templates[$hook] = array(
841178
        'template' => $template,
842178
        'path' => dirname($file->filename),
843
      );
844178
    }
845178
  }
846
847178
  $patterns = array_keys($files);
848
849178
  foreach ($cache as $hook => $info) {
850178
    if (!empty($info['pattern'])) {
851
      // Transform _ in pattern to - to match file naming scheme
852
      // for the purposes of searching.
8530
      $pattern = strtr($info['pattern'], '_', '-');
854
8550
      $matches = preg_grep('/^' . $pattern . '/', $patterns);
8560
      if ($matches) {
8570
        foreach ($matches as $match) {
8580
          $file = substr($match, 0, strpos($match, '.'));
859
          // Put the underscores back in for the hook name and register
this pattern.
8600
          $templates[strtr($file, '-', '_')] = array(
8610
            'template' => $file,
8620
            'path' => dirname($files[$match]->filename),
8630
            'arguments' => $info['arguments'],
864
          );
8650
        }
8660
      }
8670
    }
868178
  }
869178
  return $templates;
8700
}
871
872
/**
873
 * Retrieve an associative array containing the settings for a theme.
874
 *
875
 * The final settings are arrived at by merging the default settings,
876
 * the site-wide settings, and the settings defined for the specific theme.
877
 * If no $key was specified, only the site-wide theme defaults are
retrieved.
878
 *
879
 * The default values for each of settings are also defined in this
function.
880
 * To add new settings, add their default values here, and then add form
elements
881
 * to system_theme_settings() in system.module.
882
 *
883
 * @param $key
884
 *  The template/style value for a given theme.
885
 *
886
 * @return
887
 *   An associative array containing theme settings.
888
 */
8892366
function theme_get_settings($key = NULL) {
890
  $defaults = array(
8911755
    'mission'                       =>  '',
8921755
    'default_logo'                  =>  1,
8931755
    'logo_path'                     =>  '',
8941755
    'default_favicon'               =>  1,
8951755
    'favicon_path'                  =>  '',
8961755
    'main_menu'                     =>  1,
8971755
    'secondary_menu'                =>  1,
8981755
    'toggle_logo'                   =>  1,
8991755
    'toggle_favicon'                =>  1,
9001755
    'toggle_name'                   =>  1,
9011755
    'toggle_search'                 =>  1,
9021755
    'toggle_slogan'                 =>  0,
9031755
    'toggle_mission'                =>  1,
9041755
    'toggle_node_user_picture'      =>  0,
9051755
    'toggle_comment_user_picture'   =>  0,
9061755
    'toggle_main_menu'              =>  1,
9071755
    'toggle_secondary_menu'         =>  1,
9081755
  );
909
9101755
  if (module_exists('node')) {
9111753
    foreach (node_get_types() as $type => $name) {
9121753
      $defaults['toggle_node_info_' . $type] = 1;
9131753
    }
9141753
  }
9151755
  $settings = array_merge($defaults, variable_get('theme_settings',
array()));
916
9171755
  if ($key) {
9181755
    $settings = array_merge($settings, variable_get(str_replace('/', '_',
'theme_' . $key . '_settings'), array()));
9191755
  }
920
921
  // Only offer search box if search.module is enabled.
9221755
  if (!module_exists('search') || !user_access('search content')) {
9231742
    $settings['toggle_search'] = 0;
9241742
  }
925
9261755
  return $settings;
9270
}
928
929
/**
930
 * Retrieve a setting for the current theme.
931
 * This function is designed for use from within themes & engines
932
 * to determine theme settings made in the admin interface.
933
 *
934
 * Caches values for speed (use $refresh = TRUE to refresh cache)
935
 *
936
 * @param $setting_name
937
 *  The name of the setting to be retrieved.
938
 *
939
 * @param $refresh
940
 *  Whether to reload the cache of settings.
941
 *
942
 * @return
943
 *   The value of the requested setting, NULL if the setting does not
exist.
944
 */
9452366
function theme_get_setting($setting_name, $refresh = FALSE) {
9461755
  global $theme_key;
9471755
  static $settings;
948
9491755
  if (empty($settings) || $refresh) {
9501755
    $settings = theme_get_settings($theme_key);
951
9521755
    $themes = list_themes();
9531755
    $theme_object = $themes[$theme_key];
954
9551755
    if ($settings['mission'] == '') {
9561755
      $settings['mission'] = variable_get('site_mission', '');
9571755
    }
958
9591755
    if (!$settings['toggle_mission']) {
9600
      $settings['mission'] = '';
9610
    }
962
9631755
    if ($settings['toggle_logo']) {
9641755
      if ($settings['default_logo']) {
9651755
        $settings['logo'] = base_path() . dirname($theme_object->filename)
. '/logo.png';
9661755
      }
9670
      elseif ($settings['logo_path']) {
9680
        $settings['logo'] = base_path() . $settings['logo_path'];
9690
      }
9701755
    }
971
9721755
    if ($settings['toggle_favicon']) {
9731755
      if ($settings['default_favicon']) {
9741755
        if (file_exists($favicon = dirname($theme_object->filename) .
'/favicon.ico')) {
9750
          $settings['favicon'] = base_path() . $favicon;
9760
        }
977
        else {
9781755
          $settings['favicon'] = base_path() . 'misc/favicon.ico';
979
        }
9801755
      }
9810
      elseif ($settings['favicon_path']) {
9820
        $settings['favicon'] = base_path() . $settings['favicon_path'];
9830
      }
984
      else {
9850
        $settings['toggle_favicon'] = FALSE;
986
      }
9871755
    }
9881755
  }
989
9901755
  return isset($settings[$setting_name]) ? $settings[$setting_name] : NULL;
9910
}
992
993
/**
994
 * Render a system default template, which is essentially a PHP template.
995
 *
996
 * @param $file
997
 *   The filename of the template to render.
998
 * @param $variables
999
 *   A keyed array of variables that will appear in the output.
1000
 *
1001
 * @return
1002
 *   The output generated by the template.
1003
 */
10042366
function theme_render_template($file, $variables) {
10051765
  extract($variables, EXTR_SKIP);      // Extract the variables to a local
namespace
10061765
  ob_start();                          // Start output buffering
10071765
  include DRUPAL_ROOT . '/' . $file;   // Include the file
10081765
  $contents = ob_get_contents();       // Get the contents of the buffer
10091765
  ob_end_clean();                      // End buffering and discard
10101765
  return $contents;                    // Return the contents
10110
}
1012
1013
/**
1014
 * @defgroup themeable Default theme implementations
1015
 * @{
1016
 * Functions and templates that present output to the user, and can be
1017
 * implemented by themes.
1018
 *
1019
 * Drupal's presentation layer is a pluggable system known as the theme
1020
 * layer. Each theme can take control over most of Drupal's output, and
1021
 * has complete control over the CSS.
1022
 *
1023
 * Inside Drupal, the theme layer is utilized by the use of the theme()
1024
 * function, which is passed the name of a component (the theme hook)
1025
 * and several arguments. For example, theme('table', $header, $rows);
1026
 * Additionally, the theme() function can take an array of theme
1027
 * hooks, which can be used to provide 'fallback' implementations to
1028
 * allow for more specific control of output. For example, the function:
1029
 * theme(array('table__foo', 'table'), $header, $rows) would look to see if
1030
 * 'table__foo' is registered anywhere; if it is not, it would 'fall back'
1031
 * to the generic 'table' implementation. This can be used to attach
specific
1032
 * theme functions to named objects, allowing the themer more control over
1033
 * specific types of output.
1034
 *
1035
 * As of Drupal 6, every theme hook is required to be registered by the
1036
 * module that owns it, so that Drupal can tell what to do with it and
1037
 * to make it simple for themes to identify and override the behavior
1038
 * for these calls.
1039
 *
1040
 * The theme hooks are registered via hook_theme(), which returns an
1041
 * array of arrays with information about the hook. It describes the
1042
 * arguments the function or template will need, and provides
1043
 * defaults for the template in case they are not filled in. If the default
1044
 * implementation is a function, by convention it is named theme_HOOK().
1045
 *
1046
 * Each module should provide a default implementation for theme_hooks that
1047
 * it registers. This implementation may be either a function or a
template;
1048
 * if it is a function it must be specified via hook_theme(). By
convention,
1049
 * default implementations of theme hooks are named theme_HOOK. Default
1050
 * template implementations are stored in the module directory.
1051
 *
1052
 * Drupal's default template renderer is a simple PHP parsing engine that
1053
 * includes the template and stores the output. Drupal's theme engines
1054
 * can provide alternate template engines, such as XTemplate, Smarty and
1055
 * PHPTal. The most common template engine is PHPTemplate (included with
1056
 * Drupal and implemented in phptemplate.engine, which uses Drupal's
default
1057
 * template renderer.
1058
 *
1059
 * In order to create theme-specific implementations of these hooks,
1060
 * themes can implement their own version of theme hooks, either as
functions
1061
 * or templates. These implementations will be used instead of the default
1062
 * implementation. If using a pure .theme without an engine, the .theme is
1063
 * required to implement its own version of hook_theme() to tell Drupal
what
1064
 * it is implementing; themes utilizing an engine will have their
well-named
1065
 * theming functions automatically registered for them. While this can vary
1066
 * based upon the theme engine, the standard set by phptemplate is that
theme
1067
 * functions should be named either phptemplate_HOOK or THEMENAME_HOOK. For
1068
 * example, for Drupal's default theme (Garland) to implement the 'table'
hook,
1069
 * the phptemplate.engine would find phptemplate_table() or
garland_table().
1070
 * The ENGINE_HOOK() syntax is preferred, as this can be used by sub-themes
1071
 * (which are themes that share code but use different stylesheets).
1072
 *
1073
 * The theme system is described and defined in theme.inc.
1074
 *
1075
 * @see theme()
1076
 * @see hook_theme()
1077
 */
1078
1079
/**
1080
 * Formats text for emphasized display in a placeholder inside a sentence.
1081
 * Used automatically by t().
1082
 *
1083
 * @param $text
1084
 *   The text to format (plain-text).
1085
 * @return
1086
 *   The formatted text (html).
1087
 */
10882366
function theme_placeholder($text) {
1089672
  return '<em>' . check_plain($text) . '</em>';
10900
}
1091
1092
/**
1093
 * Return a themed set of status and/or error messages. The messages are
grouped
1094
 * by type.
1095
 *
1096
 * @param $display
1097
 *   (optional) Set to 'status' or 'error' to display only messages of that
type.
1098
 *
1099
 * @return
1100
 *   A string containing the messages.
1101
 */
11022366
function theme_status_messages($display = NULL) {
11031736
  $output = '';
11041736
  foreach (drupal_get_messages($display) as $type => $messages) {
1105335
    $output .= "<div class=\"messages $type\">\n";
1106335
    if (count($messages) > 1) {
110711
      $output .= " <ul>\n";
110811
      foreach ($messages as $message) {
110911
        $output .= '  <li>' . $message . "</li>\n";
111011
      }
111111
      $output .= " </ul>\n";
111211
    }
1113
    else {
1114326
      $output .= $messages[0];
1115
    }
1116335
    $output .= "</div>\n";
1117335
  }
11181736
  return $output;
11190
}
1120
1121
/**
1122
 * Return a themed set of links.
1123
 *
1124
 * @param $links
1125
 *   A keyed array of links to be themed.
1126
 * @param $attributes
1127
 *   A keyed array of attributes
1128
 * @return
1129
 *   A string containing an unordered list of links.
1130
 */
11312366
function theme_links($links, $attributes = array('class' => 'links')) {
11321755
  $output = '';
1133
11341755
  if (count($links) > 0) {
1135319
    $output = '<ul' . drupal_attributes($attributes) . '>';
1136
1137319
    $num_links = count($links);
1138319
    $i = 1;
1139
1140319
    foreach ($links as $key => $link) {
1141319
      $class = $key;
1142
1143
      // Add first, last and active classes to the list of links to help
out themers.
1144319
      if ($i == 1) {
1145319
        $class .= ' first';
1146319
      }
1147319
      if ($i == $num_links) {
1148319
        $class .= ' last';
1149319
      }
1150319
      if (isset($link['href']) && ($link['href'] == $_GET['q'] ||
($link['href'] == '<front>' && drupal_is_front_page()))) {
115135
        $class .= ' active';
115235
      }
1153319
      $output .= '<li' . drupal_attributes(array('class' => $class)) . '>';
1154
1155319
      if (isset($link['href'])) {
1156
        // Pass in $link as $options, they share the same keys.
1157315
        $output .= l($link['title'], $link['href'], $link);
1158315
      }
11594
      elseif (!empty($link['title'])) {
1160
        // Some links are actually not links, but we wrap these in <span>
for adding title and class attributes
11614
        if (empty($link['html'])) {
11620
          $link['title'] = check_plain($link['title']);
11630
        }
11644
        $span_attributes = '';
11654
        if (isset($link['attributes'])) {
11660
          $span_attributes = drupal_attributes($link['attributes']);
11670
        }
11684
        $output .= '<span' . $span_attributes . '>' . $link['title'] .
'</span>';
11694
      }
1170
1171319
      $i++;
1172319
      $output .= "</li>\n";
1173319
    }
1174
1175319
    $output .= '</ul>';
1176319
  }
1177
11781755
  return $output;
11790
}
1180
1181
/**
1182
 * Return a themed image.
1183
 *
1184
 * @param $path
1185
 *   Either the path of the image file (relative to base_path()) or a full
URL.
1186
 * @param $alt
1187
 *   The alternative text for text-based browsers.
1188
 * @param $title
1189
 *   The title text is displayed when the image is hovered in some popular
browsers.
1190
 * @param $attributes
1191
 *   Associative array of attributes to be placed in the img tag.
1192
 * @param $getsize
1193
 *   If set to TRUE, the image's dimension are fetched and added as
width/height attributes.
1194
 * @return
1195
 *   A string containing the image tag.
1196
 */
11972366
function theme_image($path, $alt = '', $title = '', $attributes = NULL,
$getsize = TRUE) {
11981741
  if (!$getsize || (is_file($path) && (list($width, $height, $type,
$image_attributes) = @getimagesize($path)))) {
11991741
    $attributes = drupal_attributes($attributes);
12001741
    $url = (url($path) == $path) ? $path : (base_path() . $path);
12011741
    return '<img src="' . check_url($url) . '" alt="' . check_plain($alt) .
'" title="' . check_plain($title) . '" ' . (isset($image_attributes) ?
$image_attributes : '') . $attributes . ' />';
12020
  }
12030
}
1204
1205
/**
1206
 * Return a themed breadcrumb trail.
1207
 *
1208
 * @param $breadcrumb
1209
 *   An array containing the breadcrumb links.
1210
 * @return a string containing the breadcrumb output.
1211
 */
12122366
function theme_breadcrumb($breadcrumb) {
12131
  if (!empty($breadcrumb)) {
12141
    return '<div class="breadcrumb">' . implode(' ยป ', $breadcrumb) .
'</div>';
12150
  }
12160
}
1217
1218
/**
1219
 * Return a themed help message.
1220
 *
1221
 * @return a string containing the helptext for the current page.
1222
 */
12232366
function theme_help() {
12241740
  if ($help = menu_get_active_help()) {
1225328
    return '<div class="help">' . $help . '</div>';
12260
  }
12271412
}
1228
1229
/**
1230
 * Return a themed submenu, typically displayed under the tabs.
1231
 *
1232
 * @param $links
1233
 *   An array of links.
1234
 */
12352366
function theme_submenu($links) {
12360
  return '<div class="submenu">' . implode(' | ', $links) . '</div>';
12370
}
1238
1239
/**
1240
 * Return a themed table.
1241
 *
1242
 * @param $header
1243
 *   An array containing the table headers. Each element of the array can
be
1244
 *   either a localized string or an associative array with the following
keys:
1245
 *   - "data": The localized title of the table column.
1246
 *   - "field": The database field represented in the table column
(required if
1247
 *     user is to be able to sort on this column).
1248
 *   - "sort": A default sort order for this column ("asc" or "desc").
1249
 *   - Any HTML attributes, such as "colspan", to apply to the column
header cell.
1250
 * @param $rows
1251
 *   An array of table rows. Every row is an array of cells, or an
associative
1252
 *   array with the following keys:
1253
 *   - "data": an array of cells
1254
 *   - Any HTML attributes, such as "class", to apply to the table row.
1255
 *
1256
 *   Each cell can be either a string or an associative array with the
following keys:
1257
 *   - "data": The string to display in the table cell.
1258
 *   - "header": Indicates this cell is a header.
1259
 *   - Any HTML attributes, such as "colspan", to apply to the table cell.
1260
 *
1261
 *   Here's an example for $rows:
1262
 *   @verbatim
1263
 *   $rows = array(
1264
 *     // Simple row
1265
 *     array(
1266
 *       'Cell 1', 'Cell 2', 'Cell 3'
1267
 *     ),
1268
 *     // Row with attributes on the row and some of its cells.
1269
 *     array(
1270
 *       'data' => array('Cell 1', array('data' => 'Cell 2', 'colspan' =>
2)), 'class' => 'funky'
1271
 *     )
1272
 *   );
1273
 *   @endverbatim
1274
 *
1275
 * @param $attributes
1276
 *   An array of HTML attributes to apply to the table tag.
1277
 * @param $caption
1278
 *   A localized string to use for the <caption> tag.
1279
 * @param $colgroups
1280
 *   An array of column groups. Each element of the array can be either:
1281
 *   - An array of columns, each of which is an associative array of HTML
attributes
1282
 *     applied to the COL element.
1283
 *   - An array of attributes applied to the COLGROUP element, which must
include a
1284
 *     "data" attribute. To add attributes to COL elements, set the "data"
attribute
1285
 *     with an array of columns, each of which is an associative array of
HTML attributes.
1286
 *   Here's an example for $colgroup:
1287
 *   @verbatim
1288
 *   $colgroup = array(
1289
 *     // COLGROUP with one COL element.
1290
 *     array(
1291
 *       array(
1292
 *         'class' => 'funky', // Attribute for the COL element.
1293
 *       ),
1294
 *     ),
1295
 *     // Colgroup with attributes and inner COL elements.
1296
 *     array(
1297
 *       'data' => array(
1298
 *         array(
1299
 *           'class' => 'funky', // Attribute for the COL element.
1300
 *         ),
1301
 *       ),
1302
 *       'class' => 'jazzy', // Attribute for the COLGROUP element.
1303
 *     ),
1304
 *   );
1305
 *   @endverbatim
1306
 *   These optional tags are used to group and set properties on columns
1307
 *   within a table. For example, one may easily group three columns and
1308
 *   apply same background style to all.
1309
 * @return
1310
 *   An HTML string representing the table.
1311
 */
13122366
function theme_table($header, $rows, $attributes = array(), $caption =
NULL, $colgroups = array()) {
1313
1314
  // Add sticky headers, if applicable.
1315263
  if (count($header)) {
1316263
    drupal_add_js('misc/tableheader.js');
1317
    // Add 'sticky-enabled' class to the table to identify it for JS.
1318
    // This is needed to target tables constructed by this function.
1319263
    $attributes['class'] = empty($attributes['class']) ? 'sticky-enabled' :
($attributes['class'] . ' sticky-enabled');
1320263
  }
1321
1322263
  $output = '<table' . drupal_attributes($attributes) . ">\n";
1323
1324263
  if (isset($caption)) {
13250
    $output .= '<caption>' . $caption . "</caption>\n";
13260
  }
1327
1328
  // Format the table columns:
1329263
  if (count($colgroups)) {
13300
    foreach ($colgroups as $number => $colgroup) {
13310
      $attributes = array();
1332
1333
      // Check if we're dealing with a simple or complex column
13340
      if (isset($colgroup['data'])) {
13350
        foreach ($colgroup as $key => $value) {
13360
          if ($key == 'data') {
13370
            $cols = $value;
13380
          }
1339
          else {
13400
            $attributes[$key] = $value;
1341
          }
13420
        }
13430
      }
1344
      else {
13450
        $cols = $colgroup;
1346
      }
1347
1348
      // Build colgroup
13490
      if (is_array($cols) && count($cols)) {
13500
        $output .= ' <colgroup' . drupal_attributes($attributes) . '>';
13510
        $i = 0;
13520
        foreach ($cols as $col) {
13530
          $output .= ' <col' . drupal_attributes($col) . ' />';
13540
        }
13550
        $output .= " </colgroup>\n";
13560
      }
1357
      else {
13580
        $output .= ' <colgroup' . drupal_attributes($attributes) . " />\n";
1359
      }
13600
    }
13610
  }
1362
1363
  // Format the table header:
1364263
  if (count($header)) {
1365263
    $ts = tablesort_init($header);
1366
    // HTML requires that the thead tag has tr tags in it follwed by tbody
1367
    // tags. Using ternary operator to check and see if we have any rows.
1368263
    $output .= (count($rows) ? ' <thead><tr>' : ' <tr>');
1369263
    foreach ($header as $cell) {
1370263
      $cell = tablesort_header($cell, $header, $ts);
1371263
      $output .= _theme_table_cell($cell, TRUE);
1372263
    }
1373
    // Using ternary operator to close the tags based on whether or not
there are rows
1374263
    $output .= (count($rows) ? " </tr></thead>\n" : "</tr>\n");
1375263
  }
1376
  else {
13770
    $ts = array();
1378
  }
1379
1380
  // Format the table rows:
1381263
  if (count($rows)) {
1382252
    $output .= "<tbody>\n";
1383252
    $flip = array('even' => 'odd', 'odd' => 'even');
1384252
    $class = 'even';
1385252
    foreach ($rows as $number => $row) {
1386252
      $attributes = array();
1387
1388
      // Check if we're dealing with a simple or complex row
1389252
      if (isset($row['data'])) {
139087
        foreach ($row as $key => $value) {
139187
          if ($key == 'data') {
139287
            $cells = $value;
139387
          }
1394
          else {
139587
            $attributes[$key] = $value;
1396
          }
139787
        }
139887
      }
1399
      else {
1400175
        $cells = $row;
1401
      }
1402252
      if (count($cells)) {
1403
        // Add odd/even class
1404252
        $class = $flip[$class];
1405252
        if (isset($attributes['class'])) {
140687
          $attributes['class'] .= ' ' . $class;
140787
        }
1408
        else {
1409175
          $attributes['class'] = $class;
1410
        }
1411
1412
        // Build row
1413252
        $output .= ' <tr' . drupal_attributes($attributes) . '>';
1414252
        $i = 0;
1415252
        foreach ($cells as $cell) {
1416252
          $cell = tablesort_cell($cell, $header, $ts, $i++);
1417252
          $output .= _theme_table_cell($cell);
1418252
        }
1419252
        $output .= " </tr>\n";
1420252
      }
1421252
    }
1422252
    $output .= "</tbody>\n";
1423252
  }
1424
1425263
  $output .= "</table>\n";
1426263
  return $output;
14270
}
1428
1429
/**
1430
 * Returns a header cell for tables that have a select all functionality.
1431
 */
14322366
function theme_table_select_header_cell() {
143326
  drupal_add_js('misc/tableselect.js');
1434
143526
  return array('class' => 'select-all');
14360
}
1437
1438
/**
1439
 * Return a themed sort icon.
1440
 *
1441
 * @param $style
1442
 *   Set to either asc or desc. This sets which icon to show.
1443
 * @return
1444
 *   A themed sort icon.
1445
 */
14462366
function theme_tablesort_indicator($style) {
144751
  if ($style == "asc") {
144845
    return theme('image', 'misc/arrow-asc.png', t('sort icon'), t('sort
ascending'));
14490
  }
1450
  else {
14516
    return theme('image', 'misc/arrow-desc.png', t('sort icon'), t('sort
descending'));
1452
  }
14530
}
1454
1455
/**
1456
 * Return a themed box.
1457
 *
1458
 * @param $title
1459
 *   The subject of the box.
1460
 * @param $content
1461
 *   The content of the box.
1462
 * @param $region
1463
 *   The region in which the box is displayed.
1464
 * @return
1465
 *   A string containing the box output.
1466
 */
14672366
function theme_box($title, $content, $region = 'main') {
14680
  $output = '<h2 class="title">' . $title . '</h2><div>' . $content .
'</div>';
14690
  return $output;
14700
}
1471
1472
/**
1473
 * Return a themed marker, useful for marking new or updated
1474
 * content.
1475
 *
1476
 * @param $type
1477
 *   Number representing the marker type to display
1478
 * @see MARK_NEW, MARK_UPDATED, MARK_READ
1479
 * @return
1480
 *   A string containing the marker.
1481
 */
14822366
function theme_mark($type = MARK_NEW) {
14838
  global $user;
14848
  if ($user->uid) {
14858
    if ($type == MARK_NEW) {
14865
      return ' <span class="marker">' . t('new') . '</span>';
14870
    }
14883
    elseif ($type == MARK_UPDATED) {
14890
      return ' <span class="marker">' . t('updated') . '</span>';
14900
    }
14913
  }
14923
}
1493
1494
/**
1495
 * Return a themed list of items.
1496
 *
1497
 * @param $items
1498
 *   An array of items to be displayed in the list. If an item is a string,
1499
 *   then it is used as is. If an item is an array, then the "data" element
of
1500
 *   the array is used as the contents of the list item. If an item is an
array
1501
 *   with a "children" element, those children are displayed in a nested
list.
1502
 *   All other elements are treated as attributes of the list item element.
1503
 * @param $title
1504
 *   The title of the list.
1505
 * @param $attributes
1506
 *   The attributes applied to the list element.
1507
 * @param $type
1508
 *   The type of list to return (e.g. "ul", "ol")
1509
 * @return
1510
 *   A string containing the list output.
1511
 */
15122366
function theme_item_list($items = array(), $title = NULL, $type = 'ul',
$attributes = array()) {
1513437
  $output = '<div class="item-list">';
1514437
  if (isset($title)) {
15151
    $output .= '<h3>' . $title . '</h3>';
15161
  }
1517
1518437
  if (!empty($items)) {
1519435
    $output .= "<$type" . drupal_attributes($attributes) . '>';
1520435
    $num_items = count($items);
1521435
    foreach ($items as $i => $item) {
1522435
      $attributes = array();
1523435
      $children = array();
1524435
      if (is_array($item)) {
15256
        foreach ($item as $key => $value) {
15266
          if ($key == 'data') {
15276
            $data = $value;
15286
          }
15296
          elseif ($key == 'children') {
15300
            $children = $value;
15310
          }
1532
          else {
15336
            $attributes[$key] = $value;
1534
          }
15356
        }
15366
      }
1537
      else {
1538429
        $data = $item;
1539
      }
1540435
      if (count($children) > 0) {
15410
        $data .= theme_item_list($children, NULL, $type, $attributes); //
Render nested list
15420
      }
1543435
      if ($i == 0) {
1544435
        $attributes['class'] = empty($attributes['class']) ? 'first' :
($attributes['class'] . ' first');
1545435
      }
1546435
      if ($i == $num_items - 1) {
1547433
        $attributes['class'] = empty($attributes['class']) ? 'last' :
($attributes['class'] . ' last');
1548433
      }
1549435
      $output .= '<li' . drupal_attributes($attributes) . '>' . $data .
"</li>\n";
1550435
    }
1551435
    $output .= "</$type>";
1552435
  }
1553437
  $output .= '</div>';
1554437
  return $output;
15550
}
1556
1557
/**
1558
 * Returns code that emits the 'more help'-link.
1559
 */
15602366
function theme_more_help_link($url) {
1561202
  return '<div class="more-help-link">' . t('<a href="@link">More
help</a>', array('@link' => check_url($url))) . '</div>';
15620
}
1563
1564
/**
1565
 * Return code that emits an XML icon.
1566
 *
1567
 * For most use cases, this function has been superseded by
theme_feed_icon().
1568
 *
1569
 * @see theme_feed_icon()
1570
 * @param $url
1571
 *   The url of the feed.
1572
 */
15732366
function theme_xml_icon($url) {
15740
  if ($image = theme('image', 'misc/xml.png', t('XML feed'), t('XML
feed'))) {
15750
    return '<a href="' . check_url($url) . '" class="xml-icon">' . $image .
'</a>';
15760
  }
15770
}
1578
1579
/**
1580
 * Return code that emits an feed icon.
1581
 *
1582
 * @param $url
1583
 *   The url of the feed.
1584
 * @param $title
1585
 *   A descriptive title of the feed.
1586
  */
15872366
function theme_feed_icon($url, $title) {
158845
  if ($image = theme('image', 'misc/feed.png', t('Syndicate content'),
$title)) {
158945
    return '<a href="' . check_url($url) . '" class="feed-icon">' . $image
. '</a>';
15900
  }
15910
}
1592
1593
/**
1594
 * Returns code that emits the 'more' link used on blocks.
1595
 *
1596
 * @param $url
1597
 *   The url of the main page
1598
 * @param $title
1599
 *   A descriptive verb for the link, like 'Read more'
1600
 */
16012366
function theme_more_link($url, $title) {
1602146
  return '<div class="more-link">' . t('<a href="@link"
title="@title">more</a>', array('@link' => check_url($url), '@title' =>
$title)) . '</div>';
16030
}
1604
1605
/**
1606
 * Execute hook_footer() which is run at the end of the page right before
the
1607
 * close of the body tag.
1608
 *
1609
 * @param $main (optional)
1610
 *   Whether the current page is the front page of the site.
1611
 * @return
1612
 *   A string containing the results of the hook_footer() calls.
1613
 */
16142366
function theme_closure($main = 0) {
16151740
  $footer = module_invoke_all('footer', $main);
16161740
  return implode("\n", $footer) . drupal_get_js('footer');
16170
}
1618
1619
/**
1620
 * Return a set of blocks available for the current user.
1621
 *
1622
 * @param $region
1623
 *   Which set of blocks to retrieve.
1624
 * @return
1625
 *   A string containing the themed blocks for this region.
1626
 */
16272366
function theme_blocks($region) {
16281740
  $output = '';
1629
16301740
  if ($list = block_list($region)) {
16311740
    foreach ($list as $key => $block) {
1632
      // $key == <i>module</i>_<i>delta</i>
16331740
      $output .= theme('block', $block);
16341740
    }
16351740
  }
1636
1637
  // Add any content assigned to this region through drupal_set_content()
calls.
16381740
  $output .= drupal_get_content($region);
1639
16401740
  return $output;
16410
}
1642
1643
/**
1644
 * Format a username.
1645
 *
1646
 * @param $object
1647
 *   The user object to format, usually returned from user_load().
1648
 * @return
1649
 *   A string containing an HTML link to the user's page if the passed
object
1650
 *   suggests that this is a site user. Otherwise, only the username is
returned.
1651
 */
16522366
function theme_username($object) {
1653
1654318
  if ($object->uid && $object->name) {
1655
    // Shorten the name when it is too long or it will break many tables.
1656302
    if (drupal_strlen($object->name) > 20) {
1657139
      $name = drupal_substr($object->name, 0, 15) . '...';
1658139
    }
1659
    else {
1660211
      $name = $object->name;
1661
    }
1662
1663302
    if (user_access('access user profiles')) {
16641
      $output = l($name, 'user/' . $object->uid, array('attributes' =>
array('title' => t('View user profile.'))));
16651
    }
1666
    else {
1667301
      $output = check_plain($name);
1668
    }
1669302
  }
167034
  elseif ($object->name) {
1671
    // Sometimes modules display content composed by people who are
1672
    // not registered members of the site (e.g. mailing list or news
1673
    // aggregator modules). This clause enables modules to display
1674
    // the true author of the content.
167518
    if (!empty($object->homepage)) {
16760
      $output = l($object->name, $object->homepage, array('attributes' =>
array('rel' => 'nofollow')));
16770
    }
1678
    else {
167918
      $output = check_plain($object->name);
1680
    }
1681
168218
    $output .= ' (' . t('not verified') . ')';
168318
  }
1684
  else {
168526
    $output = variable_get('anonymous', t('Anonymous'));
1686
  }
1687
1688318
  return $output;
16890
}
1690
1691
/**
1692
 * Return a themed progress bar.
1693
 *
1694
 * @param $percent
1695
 *   The percentage of the progress.
1696
 * @param $message
1697
 *   A string containing information to be displayed.
1698
 * @return
1699
 *   A themed HTML string representing the progress bar.
1700
 */
17012366
function theme_progress_bar($percent, $message) {
17024
  $output = '<div id="progress" class="progress">';
17034
  $output .= '<div class="bar"><div class="filled" style="width: ' .
$percent . '%"></div></div>';
17044
  $output .= '<div class="percentage">' . $percent . '%</div>';
17054
  $output .= '<div class="message">' . $message . '</div>';
17064
  $output .= '</div>';
1707
17084
  return $output;
17090
}
1710
1711
/**
1712
 * Create a standard indentation div. Used for drag and drop tables.
1713
 *
1714
 * @param $size
1715
 *   Optional. The number of indentations to create.
1716
 * @return
1717
 *   A string containing indentations.
1718
 */
17192366
function theme_indentation($size = 1) {
172034
  $output = '';
172134
  for ($n = 0; $n < $size; $n++) {
172232
    $output .= '<div class="indentation">&nbsp;</div>';
172332
  }
172434
  return $output;
17250
}
1726
1727
/**
1728
 * @} End of "defgroup themeable".
1729
 */
1730
17312366
function _theme_table_cell($cell, $header = FALSE) {
1732271
  $attributes = '';
1733
1734271
  if (is_array($cell)) {
1735238
    $data = isset($cell['data']) ? $cell['data'] : '';
1736238
    $header |= isset($cell['header']);
1737238
    unset($cell['data']);
1738238
    unset($cell['header']);
1739238
    $attributes = drupal_attributes($cell);
1740238
  }
1741
  else {
1742264
    $data = $cell;
1743
  }
1744
1745271
  if ($header) {
1746271
    $output = "<th$attributes>$data</th>";
1747271
  }
1748
  else {
1749252
    $output = "<td$attributes>$data</td>";
1750
  }
1751
1752271
  return $output;
17530
}
1754
1755
/**
1756
 * Adds a default set of helper variables for preprocess functions and
1757
 * templates. This comes in before any other preprocess function which
makes
1758
 * it possible to be used in default theme implementations (non-overriden
1759
 * theme functions).
1760
 */
17612366
function template_preprocess(&$variables, $hook) {
17621765
  global $user;
17631765
  static $count = array();
1764
1765
  // Track run count for each hook to provide zebra striping.
1766
  // See "template_preprocess_block()" which provides the same feature
specific to blocks.
17671765
  $count[$hook] = isset($count[$hook]) && is_int($count[$hook]) ?
$count[$hook] : 1;
17681765
  $variables['zebra'] = ($count[$hook] % 2) ? 'odd' : 'even';
17691765
  $variables['id'] = $count[$hook]++;
1770
1771
  // Tell all templates where they are located.
17721765
  $variables['directory'] = path_to_theme();
1773
1774
  // Set default variables that depend on the database.
17751765
  $variables['is_admin']            = FALSE;
17761765
  $variables['is_front']            = FALSE;
17771765
  $variables['logged_in']           = FALSE;
17781765
  if ($variables['db_is_active'] = db_is_active()  &&
!defined('MAINTENANCE_MODE')) {
1779
    // Check for administrators.
17801765
    if (user_access('access administration pages')) {
1781153
      $variables['is_admin'] = TRUE;
1782153
    }
1783
    // Flag front page status.
17841765
    $variables['is_front'] = drupal_is_front_page();
1785
    // Tell all templates by which kind of user they're viewed.
17861765
    $variables['logged_in'] = ($user->uid > 0);
1787
    // Provide user object to all templates
17881765
    $variables['user'] = $user;
17891765
  }
17901765
}
1791
1792
/**
1793
 * Process variables for page.tpl.php
1794
 *
1795
 * Most themes utilize their own copy of page.tpl.php. The default is
located
1796
 * inside "modules/system/page.tpl.php". Look in there for the full list of
1797
 * variables.
1798
 *
1799
 * Uses the arg() function to generate a series of page template
suggestions
1800
 * based on the current path.
1801
 *
1802
 * Any changes to variables in this preprocessor should also be changed
inside
1803
 * template_preprocess_maintenance_page() to keep all them consistent.
1804
 *
1805
 * The $variables array contains the following arguments:
1806
 * - $content
1807
 * - $show_blocks
1808
 *
1809
 * @see page.tpl.php
1810
 */
18112366
function template_preprocess_page(&$variables) {
1812
  // Add favicon
18131740
  if (theme_get_setting('toggle_favicon')) {
18141740
    drupal_set_html_head('<link rel="shortcut icon" href="' .
check_url(theme_get_setting('favicon')) . '" type="image/x-icon" />');
18151740
  }
1816
18171740
  global $theme;
1818
  // Populate all block regions.
18191740
  $regions = system_region_list($theme);
1820
  // Load all region content assigned via blocks.
18211740
  foreach (array_keys($regions) as $region) {
1822
    // Prevent left and right regions from rendering blocks when
'show_blocks' == FALSE.
18231740
    if ($variables['show_blocks'] || ($region != 'left' && $region !=
'right')) {
18241740
      $blocks = theme('blocks', $region);
18251740
    }
1826
    else {
182722
      $blocks = '';
1828
    }
1829
    // Assign region to a region variable.
18301740
    isset($variables[$region]) ? $variables[$region] .= $blocks :
$variables[$region] = $blocks;
18311740
  }
1832
1833
  // Set up layout variable.
18341740
  $variables['layout'] = 'none';
18351740
  if (!empty($variables['left'])) {
18361465
    $variables['layout'] = 'left';
18371465
  }
18381740
  if (!empty($variables['right'])) {
1839167
    $variables['layout'] = ($variables['layout'] == 'left') ? 'both' :
'right';
1840167
  }
1841
1842
  // Set mission when viewing the frontpage.
18431740
  if (drupal_is_front_page()) {
1844244
    $mission = filter_xss_admin(theme_get_setting('mission'));
1845244
  }
1846
1847
  // Construct page title
18481740
  if (drupal_get_title()) {
18491495
    $head_title = array(strip_tags(drupal_get_title()),
variable_get('site_name', 'Drupal'));
18501495
  }
1851
  else {
1852245
    $head_title = array(variable_get('site_name', 'Drupal'));
1853245
    if (variable_get('site_slogan', '')) {
18540
      $head_title[] = variable_get('site_slogan', '');
18550
    }
1856
  }
18571740
  $variables['head_title']        = implode(' | ', $head_title);
18581740
  $variables['base_path']         = base_path();
18591740
  $variables['front_page']        = url();
18601740
  $variables['breadcrumb']        = theme('breadcrumb',
drupal_get_breadcrumb());
18611740
  $variables['feed_icons']        = drupal_get_feeds();
18621740
  $variables['footer_message']    =
filter_xss_admin(variable_get('site_footer', FALSE));
18631740
  $variables['head']              = drupal_get_html_head();
18641740
  $variables['help']              = theme('help');
18651740
  $variables['language']          = $GLOBALS['language'];
18661740
  $variables['language']->dir     = $GLOBALS['language']->direction ? 'rtl'
: 'ltr';
18671740
  $variables['logo']              = theme_get_setting('logo');
18681740
  $variables['messages']          = $variables['show_messages'] ?
theme('status_messages') : '';
18691740
  $variables['mission']           = isset($mission) ? $mission : '';
18701740
  $variables['main_menu']     = theme_get_setting('toggle_main_menu') ?
menu_main_menu() : array();
18711740
  $variables['secondary_menu']   =
theme_get_setting('toggle_secondary_menu') ? menu_secondary_menu() :
array();
18721740
  $variables['search_box']        = (theme_get_setting('toggle_search') ?
drupal_get_form('search_theme_form') : '');
18731740
  $variables['site_name']         = (theme_get_setting('toggle_name') ?
variable_get('site_name', 'Drupal') : '');
18741740
  $variables['site_slogan']       = (theme_get_setting('toggle_slogan') ?
variable_get('site_slogan', '') : '');
18751740
  $variables['css']               = drupal_add_css();
18761740
  $variables['styles']            = drupal_get_css();
18771740
  $variables['scripts']           = drupal_get_js();
18781740
  $variables['tabs']              = theme('menu_local_tasks');
18791740
  $variables['title']             = drupal_get_title();
1880
  // Closure should be filled last.
18811740
  $variables['closure']           = theme('closure');
1882
18831740
  if ($node = menu_get_object()) {
1884241
    $variables['node'] = $node;
1885241
  }
1886
1887
  // Compile a list of classes that are going to be applied to the body
element.
1888
  // This allows advanced theming based on context (home page, node of
certain type, etc.).
18891740
  $body_classes = array();
1890
  // Add a class that tells us whether we're on the front page or not.
18911740
  $body_classes[] = $variables['is_front'] ? 'front' : 'not-front';
1892
  // Add a class that tells us whether the page is viewed by an
authenticated user or not.
18931740
  $body_classes[] = $variables['logged_in'] ? 'logged-in' :
'not-logged-in';
1894
  // Add arg(0) to make it possible to theme the page depending on the
current page
1895
  // type (e.g. node, admin, user, etc.). To avoid illegal characters in
the class,
1896
  // we're removing everything disallowed. We are not using 'a-z' as that
might leave
1897
  // in certain international characters (e.g. German umlauts).
18981740
  $body_classes[] = preg_replace('![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s',
'', 'page-' . form_clean_id(drupal_strtolower(arg(0))));
1899
  // If on an individual node page, add the node type.
19001740
  if (isset($variables['node']) && $variables['node']->type) {
1901241
    $body_classes[] = 'node-type-' .
form_clean_id($variables['node']->type);
1902241
  }
1903
  // Add information about the number of sidebars.
19041740
  if ($variables['layout'] == 'both') {
1905165
    $body_classes[] = 'two-sidebars';
1906165
  }
19071575
  elseif ($variables['layout'] == 'none') {
1908274
    $body_classes[] = 'no-sidebars';
1909274
  }
1910
  else {
19111302
    $body_classes[] = 'one-sidebar sidebar-' . $variables['layout'];
1912
  }
1913
  // Implode with spaces.
19141740
  $variables['body_classes'] = implode(' ', $body_classes);
1915
1916
  // Build a list of suggested template files in order of specificity. One
1917
  // suggestion is made for every element of the current path, though
1918
  // numeric elements are not carried to subsequent suggestions. For
example,
1919
  // http://www.example.com/node/1/edit would result in the following
1920
  // suggestions:
1921
  //
1922
  // page-node-edit.tpl.php
1923
  // page-node-1.tpl.php
1924
  // page-node.tpl.php
1925
  // page.tpl.php
19261740
  $i = 0;
19271740
  $suggestion = 'page';
19281740
  $suggestions = array();
19291740
  while ($arg = arg($i++)) {
19301740
    $suggestions[] = $suggestion . '-' . $arg;
19311740
    if (!is_numeric($arg)) {
19321740
      $suggestion .= '-' . $arg;
19331740
    }
19341740
  }
19351740
  if (drupal_is_front_page()) {
1936244
    $suggestions[] = 'page-front';
1937244
  }
1938
19391740
  if ($suggestions) {
19401740
    $variables['template_files'] = $suggestions;
19411740
  }
19421740
}
1943
1944
/**
1945
 * Process variables for node.tpl.php
1946
 *
1947
 * Most themes utilize their own copy of node.tpl.php. The default is
located
1948
 * inside "modules/node/node.tpl.php". Look in there for the full list of
1949
 * variables.
1950
 *
1951
 * The $variables array contains the following arguments:
1952
 * - $node
1953
 * - $teaser
1954
 * - $page
1955
 *
1956
 * @see node.tpl.php
1957
 */
19582366
function template_preprocess_node(&$variables) {
1959254
  $node = $variables['node'];
1960254
  if (module_exists('taxonomy')) {
1961254
    $variables['taxonomy'] = taxonomy_link('taxonomy terms', $node);
1962254
  }
1963
  else {
19640
    $variables['taxonomy'] = array();
1965
  }
1966
1967254
  if ($variables['teaser'] && $node->teaser) {
196824
    $variables['content'] = $node->teaser;
196924
  }
1970230
  elseif (isset($node->body)) {
1971225
    $variables['content'] = $node->body;
1972225
  }
1973
  else {
19746
    $variables['content'] = '';
1975
  }
1976
1977254
  $variables['date']      = format_date($node->created);
1978254
  $variables['links']     = !empty($node->links) ? theme('links',
$node->links, array('class' => 'links inline')) : '';
1979254
  $variables['name']      = theme('username', $node);
1980254
  $variables['node_url']  = url('node/' . $node->nid);
1981254
  $variables['terms']     = theme('links', $variables['taxonomy'],
array('class' => 'links inline'));
1982254
  $variables['title']     = check_plain($node->title);
1983
1984
  // Flatten the node object's member fields.
1985254
  $variables = array_merge((array)$node, $variables);
1986
1987
  // Display info only on certain node types.
1988254
  if (theme_get_setting('toggle_node_info_' . $node->type)) {
1989180
    $variables['submitted'] = theme('node_submitted', $node);
1990180
    $variables['picture'] = theme_get_setting('toggle_node_user_picture') ?
theme('user_picture', $node) : '';
1991180
  }
1992
  else {
199374
    $variables['submitted'] = '';
199474
    $variables['picture'] = '';
1995
  }
1996
  // Clean up name so there are no underscores.
1997254
  $variables['template_files'][] = 'node-' . str_replace('_', '-',
$node->type);
1998254
  $variables['template_files'][] = 'node-' . $node->nid;
1999254
}
2000
2001
/**
2002
 * Process variables for block.tpl.php
2003
 *
2004
 * Prepare the values passed to the theme_block function to be passed
2005
 * into a pluggable template engine. Uses block properties to generate a
2006
 * series of template file suggestions. If none are found, the default
2007
 * block.tpl.php is used.
2008
 *
2009
 * Most themes utilize their own copy of block.tpl.php. The default is
located
2010
 * inside "modules/system/block.tpl.php". Look in there for the full list
of
2011
 * variables.
2012
 *
2013
 * The $variables array contains the following arguments:
2014
 * - $block
2015
 *
2016
 * @see block.tpl.php
2017
 */
20182366
function template_preprocess_block(&$variables) {
20191740
  static $block_counter = array();
2020
  // All blocks get an independent counter for each region.
20211740
  if (!isset($block_counter[$variables['block']->region])) {
20221740
    $block_counter[$variables['block']->region] = 1;
20231740
  }
2024
  // Same with zebra striping.
20251740
  $variables['block_zebra'] = ($block_counter[$variables['block']->region]
% 2) ? 'odd' : 'even';
20261740
  $variables['block_id'] = $block_counter[$variables['block']->region]++;
2027
20281740
  $variables['template_files'][] = 'block-' . $variables['block']->region;
20291740
  $variables['template_files'][] = 'block-' . $variables['block']->module;
20301740
  $variables['template_files'][] = 'block-' . $variables['block']->module .
'-' . $variables['block']->delta;
20311740
}
20322366