Mercurial > defr > drupal > core
comparison includes/theme.inc @ 1:c1f4ac30525a 6.0
Drupal 6.0
| author | Franck Deroche <webmaster@defr.org> |
|---|---|
| date | Tue, 23 Dec 2008 14:28:28 +0100 |
| parents | |
| children | 2427550111ae |
comparison
equal
deleted
inserted
replaced
| 0:5a113a1c4740 | 1:c1f4ac30525a |
|---|---|
| 1 <?php | |
| 2 // $Id: theme.inc,v 1.415 2008/01/27 19:47:06 goba 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 define('MARK_READ', 0); | |
| 22 define('MARK_NEW', 1); | |
| 23 define('MARK_UPDATED', 2); | |
| 24 /** | |
| 25 * @} End of "Content markers". | |
| 26 */ | |
| 27 | |
| 28 /** | |
| 29 * Initialize the theme system by loading the theme. | |
| 30 */ | |
| 31 function init_theme() { | |
| 32 global $theme, $user, $custom_theme, $theme_key; | |
| 33 | |
| 34 // If $theme is already set, assume the others are set, too, and do nothing | |
| 35 if (isset($theme)) { | |
| 36 return; | |
| 37 } | |
| 38 | |
| 39 drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE); | |
| 40 $themes = list_themes(); | |
| 41 | |
| 42 // Only select the user selected theme if it is available in the | |
| 43 // list of enabled themes. | |
| 44 $theme = !empty($user->theme) && !empty($themes[$user->theme]->status) ? $user->theme : variable_get('theme_default', 'garland'); | |
| 45 | |
| 46 // Allow modules to override the present theme... only select custom theme | |
| 47 // if it is available in the list of installed themes. | |
| 48 $theme = $custom_theme && $themes[$custom_theme] ? $custom_theme : $theme; | |
| 49 | |
| 50 // Store the identifier for retrieving theme settings with. | |
| 51 $theme_key = $theme; | |
| 52 | |
| 53 // Find all our ancestor themes and put them in an array. | |
| 54 $base_theme = array(); | |
| 55 $ancestor = $theme; | |
| 56 while ($ancestor && isset($themes[$ancestor]->base_theme)) { | |
| 57 $base_theme[] = $new_base_theme = $themes[$themes[$ancestor]->base_theme]; | |
| 58 $ancestor = $themes[$ancestor]->base_theme; | |
| 59 } | |
| 60 _init_theme($themes[$theme], array_reverse($base_theme)); | |
| 61 } | |
| 62 | |
| 63 /** | |
| 64 * Initialize the theme system given already loaded information. This | |
| 65 * function is useful to initialize a theme when no database is present. | |
| 66 * | |
| 67 * @param $theme | |
| 68 * An object with the following information: | |
| 69 * filename | |
| 70 * The .info file for this theme. The 'path' to | |
| 71 * the theme will be in this file's directory. (Required) | |
| 72 * owner | |
| 73 * The path to the .theme file or the .engine file to load for | |
| 74 * the theme. (Required) | |
| 75 * stylesheet | |
| 76 * The primary stylesheet for the theme. (Optional) | |
| 77 * engine | |
| 78 * The name of theme engine to use. (Optional) | |
| 79 * @param $base_theme | |
| 80 * An optional array of objects that represent the 'base theme' if the | |
| 81 * theme is meant to be derivative of another theme. It requires | |
| 82 * the same information as the $theme object. It should be in | |
| 83 * 'oldest first' order, meaning the top level of the chain will | |
| 84 * be first. | |
| 85 * @param $registry_callback | |
| 86 * The callback to invoke to set the theme registry. | |
| 87 */ | |
| 88 function _init_theme($theme, $base_theme = array(), $registry_callback = '_theme_load_registry') { | |
| 89 global $theme_info, $base_theme_info, $theme_engine, $theme_path; | |
| 90 $theme_info = $theme; | |
| 91 $base_theme_info = $base_theme; | |
| 92 | |
| 93 $theme_path = dirname($theme->filename); | |
| 94 | |
| 95 // Prepare stylesheets from this theme as well as all ancestor themes. | |
| 96 // We work it this way so that we can have child themes override parent | |
| 97 // theme stylesheets easily. | |
| 98 $final_stylesheets = array(); | |
| 99 | |
| 100 // Grab stylesheets from base theme | |
| 101 foreach ($base_theme as $base) { | |
| 102 if (!empty($base->stylesheets)) { | |
| 103 foreach ($base->stylesheets as $media => $stylesheets) { | |
| 104 foreach ($stylesheets as $name => $stylesheet) { | |
| 105 $final_stylesheets[$media][$name] = $stylesheet; | |
| 106 } | |
| 107 } | |
| 108 } | |
| 109 } | |
| 110 | |
| 111 // Add stylesheets used by this theme. | |
| 112 if (!empty($theme->stylesheets)) { | |
| 113 foreach ($theme->stylesheets as $media => $stylesheets) { | |
| 114 foreach ($stylesheets as $name => $stylesheet) { | |
| 115 $final_stylesheets[$media][$name] = $stylesheet; | |
| 116 } | |
| 117 } | |
| 118 } | |
| 119 | |
| 120 // And now add the stylesheets properly | |
| 121 foreach ($final_stylesheets as $media => $stylesheets) { | |
| 122 foreach ($stylesheets as $stylesheet) { | |
| 123 drupal_add_css($stylesheet, 'theme', $media); | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 // Do basically the same as the above for scripts | |
| 128 $final_scripts = array(); | |
| 129 | |
| 130 // Grab scripts from base theme | |
| 131 foreach ($base_theme as $base) { | |
| 132 if (!empty($base->scripts)) { | |
| 133 foreach ($base->scripts as $name => $script) { | |
| 134 $final_scripts[$name] = $script; | |
| 135 } | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 // Add scripts used by this theme. | |
| 140 if (!empty($theme->scripts)) { | |
| 141 foreach ($theme->scripts as $name => $script) { | |
| 142 $final_scripts[$name] = $script; | |
| 143 } | |
| 144 } | |
| 145 | |
| 146 // Add scripts used by this theme. | |
| 147 foreach ($final_scripts as $script) { | |
| 148 drupal_add_js($script, 'theme'); | |
| 149 } | |
| 150 | |
| 151 $theme_engine = NULL; | |
| 152 | |
| 153 // Initialize the theme. | |
| 154 if (isset($theme->engine)) { | |
| 155 // Include the engine. | |
| 156 include_once './'. $theme->owner; | |
| 157 | |
| 158 $theme_engine = $theme->engine; | |
| 159 if (function_exists($theme_engine .'_init')) { | |
| 160 foreach ($base_theme as $base) { | |
| 161 call_user_func($theme_engine .'_init', $base); | |
| 162 } | |
| 163 call_user_func($theme_engine .'_init', $theme); | |
| 164 } | |
| 165 } | |
| 166 else { | |
| 167 // include non-engine theme files | |
| 168 foreach ($base_theme as $base) { | |
| 169 // Include the theme file or the engine. | |
| 170 if (!empty($base->owner)) { | |
| 171 include_once './'. $base->owner; | |
| 172 } | |
| 173 } | |
| 174 // and our theme gets one too. | |
| 175 if (!empty($theme->owner)) { | |
| 176 include_once './'. $theme->owner; | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 $registry_callback($theme, $base_theme, $theme_engine); | |
| 181 } | |
| 182 | |
| 183 /** | |
| 184 * Retrieve the stored theme registry. If the theme registry is already | |
| 185 * in memory it will be returned; otherwise it will attempt to load the | |
| 186 * registry from cache. If this fails, it will construct the registry and | |
| 187 * cache it. | |
| 188 */ | |
| 189 function theme_get_registry($registry = NULL) { | |
| 190 static $theme_registry = NULL; | |
| 191 if (isset($registry)) { | |
| 192 $theme_registry = $registry; | |
| 193 } | |
| 194 | |
| 195 return $theme_registry; | |
| 196 } | |
| 197 | |
| 198 /** | |
| 199 * Store the theme registry in memory. | |
| 200 */ | |
| 201 function _theme_set_registry($registry) { | |
| 202 // Pass through for setting of static variable. | |
| 203 return theme_get_registry($registry); | |
| 204 } | |
| 205 | |
| 206 /** | |
| 207 * Get the theme_registry cache from the database; if it doesn't exist, build | |
| 208 * it. | |
| 209 * | |
| 210 * @param $theme | |
| 211 * The loaded $theme object. | |
| 212 * @param $base_theme | |
| 213 * An array of loaded $theme objects representing the ancestor themes in | |
| 214 * oldest first order. | |
| 215 * @param theme_engine | |
| 216 * The name of the theme engine. | |
| 217 */ | |
| 218 function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL) { | |
| 219 // Check the theme registry cache; if it exists, use it. | |
| 220 $cache = cache_get("theme_registry:$theme->name", 'cache'); | |
| 221 if (isset($cache->data)) { | |
| 222 $registry = $cache->data; | |
| 223 } | |
| 224 else { | |
| 225 // If not, build one and cache it. | |
| 226 $registry = _theme_build_registry($theme, $base_theme, $theme_engine); | |
| 227 _theme_save_registry($theme, $registry); | |
| 228 } | |
| 229 _theme_set_registry($registry); | |
| 230 } | |
| 231 | |
| 232 /** | |
| 233 * Write the theme_registry cache into the database. | |
| 234 */ | |
| 235 function _theme_save_registry($theme, $registry) { | |
| 236 cache_set("theme_registry:$theme->name", $registry); | |
| 237 } | |
| 238 | |
| 239 /** | |
| 240 * Force the system to rebuild the theme registry; this should be called | |
| 241 * when modules are added to the system, or when a dynamic system needs | |
| 242 * to add more theme hooks. | |
| 243 */ | |
| 244 function drupal_rebuild_theme_registry() { | |
| 245 cache_clear_all('theme_registry', 'cache', TRUE); | |
| 246 } | |
| 247 | |
| 248 /** | |
| 249 * Process a single invocation of the theme hook. $type will be one | |
| 250 * of 'module', 'theme_engine' or 'theme' and it tells us some | |
| 251 * important information. | |
| 252 * | |
| 253 * Because $cache is a reference, the cache will be continually | |
| 254 * expanded upon; new entries will replace old entries in the | |
| 255 * array_merge, but we are careful to ensure some data is carried | |
| 256 * forward, such as the arguments a theme hook needs. | |
| 257 * | |
| 258 * An override flag can be set for preprocess functions. When detected the | |
| 259 * cached preprocessors for the hook will not be merged with the newly set. | |
| 260 * This can be useful to themes and theme engines by giving them more control | |
| 261 * over how and when the preprocess functions are run. | |
| 262 */ | |
| 263 function _theme_process_registry(&$cache, $name, $type, $theme, $path) { | |
| 264 $function = $name .'_theme'; | |
| 265 if (function_exists($function)) { | |
| 266 $result = $function($cache, $type, $theme, $path); | |
| 267 | |
| 268 foreach ($result as $hook => $info) { | |
| 269 $result[$hook]['type'] = $type; | |
| 270 $result[$hook]['theme path'] = $path; | |
| 271 // if function and file are left out, default to standard naming | |
| 272 // conventions. | |
| 273 if (!isset($info['template']) && !isset($info['function'])) { | |
| 274 $result[$hook]['function'] = ($type == 'module' ? 'theme_' : $name .'_') . $hook; | |
| 275 } | |
| 276 // If a path is set in the info, use what was set. Otherwise use the | |
| 277 // default path. This is mostly so system.module can declare theme | |
| 278 // functions on behalf of core .include files. | |
| 279 // All files are included to be safe. Conditionally included | |
| 280 // files can prevent them from getting registered. | |
| 281 if (isset($info['file']) && !isset($info['path'])) { | |
| 282 $result[$hook]['file'] = $path .'/'. $info['file']; | |
| 283 include_once($result[$hook]['file']); | |
| 284 } | |
| 285 elseif (isset($info['file']) && isset($info['path'])) { | |
| 286 include_once($info['path'] .'/'. $info['file']); | |
| 287 } | |
| 288 | |
| 289 if (isset($info['template']) && !isset($info['path'])) { | |
| 290 $result[$hook]['template'] = $path .'/'. $info['template']; | |
| 291 } | |
| 292 // If 'arguments' have been defined previously, carry them forward. | |
| 293 // This should happen if a theme overrides a Drupal defined theme | |
| 294 // function, for example. | |
| 295 if (!isset($info['arguments']) && isset($cache[$hook])) { | |
| 296 $result[$hook]['arguments'] = $cache[$hook]['arguments']; | |
| 297 } | |
| 298 // Likewise with theme paths. These are used for template naming suggestions. | |
| 299 // Theme implementations can occur in multiple paths. Suggestions should follow. | |
| 300 if (!isset($info['theme paths']) && isset($cache[$hook])) { | |
| 301 $result[$hook]['theme paths'] = $cache[$hook]['theme paths']; | |
| 302 } | |
| 303 // Check for sub-directories. | |
| 304 $result[$hook]['theme paths'][] = isset($info['path']) ? $info['path'] : $path; | |
| 305 | |
| 306 // Check for default _preprocess_ functions. Ensure arrayness. | |
| 307 if (!isset($info['preprocess functions']) || !is_array($info['preprocess functions'])) { | |
| 308 $info['preprocess functions'] = array(); | |
| 309 $prefixes = array(); | |
| 310 if ($type == 'module') { | |
| 311 // Default preprocessor prefix. | |
| 312 $prefixes[] = 'template'; | |
| 313 // Add all modules so they can intervene with their own preprocessors. This allows them | |
| 314 // to provide preprocess functions even if they are not the owner of the current hook. | |
| 315 $prefixes += module_list(); | |
| 316 } | |
| 317 elseif ($type == 'theme_engine') { | |
| 318 // Theme engines get an extra set that come before the normally named preprocessors. | |
| 319 $prefixes[] = $name .'_engine'; | |
| 320 // The theme engine also registers on behalf of the theme. The theme or engine name can be used. | |
| 321 $prefixes[] = $name; | |
| 322 $prefixes[] = $theme; | |
| 323 } | |
| 324 else { | |
| 325 // This applies when the theme manually registers their own preprocessors. | |
| 326 $prefixes[] = $name; | |
| 327 } | |
| 328 | |
| 329 foreach ($prefixes as $prefix) { | |
| 330 if (function_exists($prefix .'_preprocess')) { | |
| 331 $info['preprocess functions'][] = $prefix .'_preprocess'; | |
| 332 } | |
| 333 if (function_exists($prefix .'_preprocess_'. $hook)) { | |
| 334 $info['preprocess functions'][] = $prefix .'_preprocess_'. $hook; | |
| 335 } | |
| 336 } | |
| 337 } | |
| 338 // Check for the override flag and prevent the cached preprocess functions from being used. | |
| 339 // This allows themes or theme engines to remove preprocessors set earlier in the registry build. | |
| 340 if (!empty($info['override preprocess functions'])) { | |
| 341 // Flag not needed inside the registry. | |
| 342 unset($result[$hook]['override preprocess functions']); | |
| 343 } | |
| 344 elseif (isset($cache[$hook]['preprocess functions']) && is_array($cache[$hook]['preprocess functions'])) { | |
| 345 $info['preprocess functions'] = array_merge($cache[$hook]['preprocess functions'], $info['preprocess functions']); | |
| 346 } | |
| 347 $result[$hook]['preprocess functions'] = $info['preprocess functions']; | |
| 348 } | |
| 349 | |
| 350 // Merge the newly created theme hooks into the existing cache. | |
| 351 $cache = array_merge($cache, $result); | |
| 352 } | |
| 353 } | |
| 354 | |
| 355 /** | |
| 356 * Rebuild the hook theme_registry cache. | |
| 357 * | |
| 358 * @param $theme | |
| 359 * The loaded $theme object. | |
| 360 * @param $base_theme | |
| 361 * An array of loaded $theme objects representing the ancestor themes in | |
| 362 * oldest first order. | |
| 363 * @param theme_engine | |
| 364 * The name of the theme engine. | |
| 365 */ | |
| 366 function _theme_build_registry($theme, $base_theme, $theme_engine) { | |
| 367 $cache = array(); | |
| 368 // First, process the theme hooks advertised by modules. This will | |
| 369 // serve as the basic registry. | |
| 370 foreach (module_implements('theme') as $module) { | |
| 371 _theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module)); | |
| 372 } | |
| 373 | |
| 374 // Process each base theme. | |
| 375 foreach ($base_theme as $base) { | |
| 376 // If the theme uses a theme engine, process its hooks. | |
| 377 $base_path = dirname($base->filename); | |
| 378 if ($theme_engine) { | |
| 379 _theme_process_registry($cache, $theme_engine, 'base_theme_engine', $base->name, $base_path); | |
| 380 } | |
| 381 _theme_process_registry($cache, $base->name, 'base_theme', $base->name, $base_path); | |
| 382 } | |
| 383 | |
| 384 // And then the same thing, but for the theme. | |
| 385 if ($theme_engine) { | |
| 386 _theme_process_registry($cache, $theme_engine, 'theme_engine', $theme->name, dirname($theme->filename)); | |
| 387 } | |
| 388 | |
| 389 // Finally, hooks provided by the theme itself. | |
| 390 _theme_process_registry($cache, $theme->name, 'theme', $theme->name, dirname($theme->filename)); | |
| 391 | |
| 392 // Let modules alter the registry | |
| 393 drupal_alter('theme_registry', $cache); | |
| 394 return $cache; | |
| 395 } | |
| 396 | |
| 397 /** | |
| 398 * Provides a list of currently available themes. | |
| 399 * | |
| 400 * If the database is active then it will be retrieved from the database. | |
| 401 * Otherwise it will retrieve a new list. | |
| 402 * | |
| 403 * @param $refresh | |
| 404 * Whether to reload the list of themes from the database. | |
| 405 * @return | |
| 406 * An array of the currently available themes. | |
| 407 */ | |
| 408 function list_themes($refresh = FALSE) { | |
| 409 static $list = array(); | |
| 410 | |
| 411 if ($refresh) { | |
| 412 $list = array(); | |
| 413 } | |
| 414 | |
| 415 if (empty($list)) { | |
| 416 $list = array(); | |
| 417 $themes = array(); | |
| 418 // Extract from the database only when it is available. | |
| 419 // Also check that the site is not in the middle of an install or update. | |
| 420 if (db_is_active() && !defined('MAINTENANCE_MODE')) { | |
| 421 $result = db_query("SELECT * FROM {system} WHERE type = '%s'", 'theme'); | |
| 422 while ($theme = db_fetch_object($result)) { | |
| 423 if (file_exists($theme->filename)) { | |
| 424 $theme->info = unserialize($theme->info); | |
| 425 $themes[] = $theme; | |
| 426 } | |
| 427 } | |
| 428 } | |
| 429 else { | |
| 430 // Scan the installation when the database should not be read. | |
| 431 $themes = _system_theme_data(); | |
| 432 } | |
| 433 | |
| 434 foreach ($themes as $theme) { | |
| 435 foreach ($theme->info['stylesheets'] as $media => $stylesheets) { | |
| 436 foreach ($stylesheets as $stylesheet => $path) { | |
| 437 if (file_exists($path)) { | |
| 438 $theme->stylesheets[$media][$stylesheet] = $path; | |
| 439 } | |
| 440 } | |
| 441 } | |
| 442 foreach ($theme->info['scripts'] as $script => $path) { | |
| 443 if (file_exists($path)) { | |
| 444 $theme->scripts[$script] = $path; | |
| 445 } | |
| 446 } | |
| 447 if (isset($theme->info['engine'])) { | |
| 448 $theme->engine = $theme->info['engine']; | |
| 449 } | |
| 450 if (isset($theme->info['base theme'])) { | |
| 451 $theme->base_theme = $theme->info['base theme']; | |
| 452 } | |
| 453 // Status is normally retrieved from the database. Add zero values when | |
| 454 // read from the installation directory to prevent notices. | |
| 455 if (!isset($theme->status)) { | |
| 456 $theme->status = 0; | |
| 457 } | |
| 458 $list[$theme->name] = $theme; | |
| 459 } | |
| 460 } | |
| 461 | |
| 462 return $list; | |
| 463 } | |
| 464 | |
| 465 /** | |
| 466 * Generate the themed output. | |
| 467 * | |
| 468 * All requests for theme hooks must go through this function. It examines | |
| 469 * the request and routes it to the appropriate theme function. The theme | |
| 470 * registry is checked to determine which implementation to use, which may | |
| 471 * be a function or a template. | |
| 472 * | |
| 473 * If the implementation is a function, it is executed and its return value | |
| 474 * passed along. | |
| 475 * | |
| 476 * If the implementation is a template, the arguments are converted to a | |
| 477 * $variables array. This array is then modified by the module implementing | |
| 478 * the hook, theme engine (if applicable) and the theme. The following | |
| 479 * functions may be used to modify the $variables array. They are processed in | |
| 480 * this order when available: | |
| 481 * | |
| 482 * - template_preprocess(&$variables) | |
| 483 * This sets a default set of variables for all template implementations. | |
| 484 * | |
| 485 * - template_preprocess_HOOK(&$variables) | |
| 486 * This is the first preprocessor called specific to the hook; it should be | |
| 487 * implemented by the module that registers it. | |
| 488 * | |
| 489 * - MODULE_preprocess(&$variables) | |
| 490 * This will be called for all templates; it should only be used if there | |
| 491 * is a real need. It's purpose is similar to template_preprocess(). | |
| 492 * | |
| 493 * - MODULE_preprocess_HOOK(&$variables) | |
| 494 * This is for modules that want to alter or provide extra variables for | |
| 495 * theming hooks not registered to itself. For example, if a module named | |
| 496 * "foo" wanted to alter the $submitted variable for the hook "node" a | |
| 497 * preprocess function of foo_preprocess_node() can be created to intercept | |
| 498 * and alter the variable. | |
| 499 * | |
| 500 * - ENGINE_engine_preprocess(&$variables) | |
| 501 * This function should only be implemented by theme engines and exists | |
| 502 * so that it can set necessary variables for all hooks. | |
| 503 * | |
| 504 * - ENGINE_engine_preprocess_HOOK(&$variables) | |
| 505 * This is the same as the previous function, but it is called for a single | |
| 506 * theming hook. | |
| 507 * | |
| 508 * - ENGINE_preprocess(&$variables) | |
| 509 * This is meant to be used by themes that utilize a theme engine. It is | |
| 510 * provided so that the preprocessor is not locked into a specific theme. | |
| 511 * This makes it easy to share and transport code but theme authors must be | |
| 512 * careful to prevent fatal re-declaration errors when using sub-themes that | |
| 513 * have their own preprocessor named exactly the same as its base theme. In | |
| 514 * the default theme engine (PHPTemplate), sub-themes will load their own | |
| 515 * template.php file in addition to the one used for its parent theme. This | |
| 516 * increases the risk for these errors. A good practice is to use the engine | |
| 517 * name for the base theme and the theme name for the sub-themes to minimize | |
| 518 * this possibility. | |
| 519 * | |
| 520 * - ENGINE_preprocess_HOOK(&$variables) | |
| 521 * The same applies from the previous function, but it is called for a | |
| 522 * specific hook. | |
| 523 * | |
| 524 * - THEME_preprocess(&$variables) | |
| 525 * These functions are based upon the raw theme; they should primarily be | |
| 526 * used by themes that do not use an engine or by sub-themes. It serves the | |
| 527 * same purpose as ENGINE_preprocess(). | |
| 528 * | |
| 529 * - THEME_preprocess_HOOK(&$variables) | |
| 530 * The same applies from the previous function, but it is called for a | |
| 531 * specific hook. | |
| 532 * | |
| 533 * There are two special variables that these hooks can set: | |
| 534 * 'template_file' and 'template_files'. These will be merged together | |
| 535 * to form a list of 'suggested' alternate template files to use, in | |
| 536 * reverse order of priority. template_file will always be a higher | |
| 537 * priority than items in template_files. theme() will then look for these | |
| 538 * files, one at a time, and use the first one | |
| 539 * that exists. | |
| 540 * @param $hook | |
| 541 * The name of the theme function to call. May be an array, in which | |
| 542 * case the first hook that actually has an implementation registered | |
| 543 * will be used. This can be used to choose 'fallback' theme implementations, | |
| 544 * so that if the specific theme hook isn't implemented anywhere, a more | |
| 545 * generic one will be used. This can allow themes to create specific theme | |
| 546 * implementations for named objects. | |
| 547 * @param ... | |
| 548 * Additional arguments to pass along to the theme function. | |
| 549 * @return | |
| 550 * An HTML string that generates the themed output. | |
| 551 */ | |
| 552 function theme() { | |
| 553 $args = func_get_args(); | |
| 554 $hook = array_shift($args); | |
| 555 | |
| 556 static $hooks = NULL; | |
| 557 if (!isset($hooks)) { | |
| 558 init_theme(); | |
| 559 $hooks = theme_get_registry(); | |
| 560 } | |
| 561 | |
| 562 if (is_array($hook)) { | |
| 563 foreach ($hook as $candidate) { | |
| 564 if (isset($hooks[$candidate])) { | |
| 565 break; | |
| 566 } | |
| 567 } | |
| 568 $hook = $candidate; | |
| 569 } | |
| 570 | |
| 571 if (!isset($hooks[$hook])) { | |
| 572 return; | |
| 573 } | |
| 574 | |
| 575 $info = $hooks[$hook]; | |
| 576 global $theme_path; | |
| 577 $temp = $theme_path; | |
| 578 // point path_to_theme() to the currently used theme path: | |
| 579 $theme_path = $hooks[$hook]['theme path']; | |
| 580 | |
| 581 // Include a file if the theme function or preprocess function is held elsewhere. | |
| 582 if (!empty($info['file'])) { | |
| 583 $include_file = $info['file']; | |
| 584 if (isset($info['path'])) { | |
| 585 $include_file = $info['path'] .'/'. $include_file; | |
| 586 } | |
| 587 include_once($include_file); | |
| 588 } | |
| 589 if (isset($info['function'])) { | |
| 590 // The theme call is a function. | |
| 591 $output = call_user_func_array($info['function'], $args); | |
| 592 } | |
| 593 else { | |
| 594 // The theme call is a template. | |
| 595 $variables = array( | |
| 596 'template_files' => array() | |
| 597 ); | |
| 598 if (!empty($info['arguments'])) { | |
| 599 $count = 0; | |
| 600 foreach ($info['arguments'] as $name => $default) { | |
| 601 $variables[$name] = isset($args[$count]) ? $args[$count] : $default; | |
| 602 $count++; | |
| 603 } | |
| 604 } | |
| 605 | |
| 606 // default render function and extension. | |
| 607 $render_function = 'theme_render_template'; | |
| 608 $extension = '.tpl.php'; | |
| 609 | |
| 610 // Run through the theme engine variables, if necessary | |
| 611 global $theme_engine; | |
| 612 if (isset($theme_engine)) { | |
| 613 // If theme or theme engine is implementing this, it may have | |
| 614 // a different extension and a different renderer. | |
| 615 if ($hooks[$hook]['type'] != 'module') { | |
| 616 if (function_exists($theme_engine .'_render_template')) { | |
| 617 $render_function = $theme_engine .'_render_template'; | |
| 618 } | |
| 619 $extension_function = $theme_engine .'_extension'; | |
| 620 if (function_exists($extension_function)) { | |
| 621 $extension = $extension_function(); | |
| 622 } | |
| 623 } | |
| 624 } | |
| 625 | |
| 626 if (isset($info['preprocess functions']) && is_array($info['preprocess functions'])) { | |
| 627 // This construct ensures that we can keep a reference through | |
| 628 // call_user_func_array. | |
| 629 $args = array(&$variables, $hook); | |
| 630 foreach ($info['preprocess functions'] as $preprocess_function) { | |
| 631 if (function_exists($preprocess_function)) { | |
| 632 call_user_func_array($preprocess_function, $args); | |
| 633 } | |
| 634 } | |
| 635 } | |
| 636 | |
| 637 // Get suggestions for alternate templates out of the variables | |
| 638 // that were set. This lets us dynamically choose a template | |
| 639 // from a list. The order is FILO, so this array is ordered from | |
| 640 // least appropriate first to most appropriate last. | |
| 641 $suggestions = array(); | |
| 642 | |
| 643 if (isset($variables['template_files'])) { | |
| 644 $suggestions = $variables['template_files']; | |
| 645 } | |
| 646 if (isset($variables['template_file'])) { | |
| 647 $suggestions[] = $variables['template_file']; | |
| 648 } | |
| 649 | |
| 650 if ($suggestions) { | |
| 651 $template_file = drupal_discover_template($info['theme paths'], $suggestions, $extension); | |
| 652 } | |
| 653 | |
| 654 if (empty($template_file)) { | |
| 655 $template_file = $hooks[$hook]['template'] . $extension; | |
| 656 if (isset($hooks[$hook]['path'])) { | |
| 657 $template_file = $hooks[$hook]['path'] .'/'. $template_file; | |
| 658 } | |
| 659 } | |
| 660 $output = $render_function($template_file, $variables); | |
| 661 } | |
| 662 // restore path_to_theme() | |
| 663 $theme_path = $temp; | |
| 664 return $output; | |
| 665 } | |
| 666 | |
| 667 /** | |
| 668 * Choose which template file to actually render. These are all suggested | |
| 669 * templates from themes and modules. Theming implementations can occur on | |
| 670 * multiple levels. All paths are checked to account for this. | |
| 671 */ | |
| 672 function drupal_discover_template($paths, $suggestions, $extension = '.tpl.php') { | |
| 673 global $theme_engine; | |
| 674 | |
| 675 // Loop through all paths and suggestions in FIFO order. | |
| 676 $suggestions = array_reverse($suggestions); | |
| 677 $paths = array_reverse($paths); | |
| 678 foreach ($suggestions as $suggestion) { | |
| 679 if (!empty($suggestion)) { | |
| 680 foreach ($paths as $path) { | |
| 681 if (file_exists($file = $path .'/'. $suggestion . $extension)) { | |
| 682 return $file; | |
| 683 } | |
| 684 } | |
| 685 } | |
| 686 } | |
| 687 } | |
| 688 | |
| 689 /** | |
| 690 * Return the path to the currently selected theme. | |
| 691 */ | |
| 692 function path_to_theme() { | |
| 693 global $theme_path; | |
| 694 | |
| 695 if (!isset($theme_path)) { | |
| 696 init_theme(); | |
| 697 } | |
| 698 | |
| 699 return $theme_path; | |
| 700 } | |
| 701 | |
| 702 /** | |
| 703 * Find overridden theme functions. Called by themes and/or theme engines to | |
| 704 * easily discover theme functions. | |
| 705 * | |
| 706 * @param $cache | |
| 707 * The existing cache of theme hooks to test against. | |
| 708 * @param $prefixes | |
| 709 * An array of prefixes to test, in reverse order of importance. | |
| 710 * | |
| 711 * @return $templates | |
| 712 * The functions found, suitable for returning from hook_theme; | |
| 713 */ | |
| 714 function drupal_find_theme_functions($cache, $prefixes) { | |
| 715 $templates = array(); | |
| 716 $functions = get_defined_functions(); | |
| 717 | |
| 718 foreach ($cache as $hook => $info) { | |
| 719 foreach ($prefixes as $prefix) { | |
| 720 if (!empty($info['pattern'])) { | |
| 721 $matches = preg_grep('/^'. $prefix .'_'. $info['pattern'] .'/', $functions['user']); | |
| 722 if ($matches) { | |
| 723 foreach ($matches as $match) { | |
| 724 $new_hook = str_replace($prefix .'_', '', $match); | |
| 725 $templates[$new_hook] = array( | |
| 726 'function' => $match, | |
| 727 'arguments' => $info['arguments'], | |
| 728 ); | |
| 729 } | |
| 730 } | |
| 731 } | |
| 732 if (function_exists($prefix .'_'. $hook)) { | |
| 733 $templates[$hook] = array( | |
| 734 'function' => $prefix .'_'. $hook, | |
| 735 ); | |
| 736 } | |
| 737 } | |
| 738 } | |
| 739 | |
| 740 return $templates; | |
| 741 } | |
| 742 | |
| 743 /** | |
| 744 * Find overridden theme templates. Called by themes and/or theme engines to | |
| 745 * easily discover templates. | |
| 746 * | |
| 747 * @param $cache | |
| 748 * The existing cache of theme hooks to test against. | |
| 749 * @param $extension | |
| 750 * The extension that these templates will have. | |
| 751 * @param $path | |
| 752 * The path to search. | |
| 753 */ | |
| 754 function drupal_find_theme_templates($cache, $extension, $path) { | |
| 755 $templates = array(); | |
| 756 | |
| 757 // Collect paths to all sub-themes grouped by base themes. These will be | |
| 758 // used for filtering. This allows base themes to have sub-themes in its | |
| 759 // folder hierarchy without affecting the base themes template discovery. | |
| 760 $theme_paths = array(); | |
| 761 foreach (list_themes() as $theme_info) { | |
| 762 if (!empty($theme_info->base_theme)) { | |
| 763 $theme_paths[$theme_info->base_theme][$theme_info->name] = dirname($theme_info->filename); | |
| 764 } | |
| 765 } | |
| 766 foreach ($theme_paths as $basetheme => $subthemes) { | |
| 767 foreach ($subthemes as $subtheme => $subtheme_path) { | |
| 768 if (isset($theme_paths[$subtheme])) { | |
| 769 $theme_paths[$basetheme] = array_merge($theme_paths[$basetheme], $theme_paths[$subtheme]); | |
| 770 } | |
| 771 } | |
| 772 } | |
| 773 global $theme; | |
| 774 $subtheme_paths = isset($theme_paths[$theme]) ? $theme_paths[$theme] : array(); | |
| 775 | |
| 776 // Escape the periods in the extension. | |
| 777 $regex = str_replace('.', '\.', $extension) .'$'; | |
| 778 // Because drupal_system_listing works the way it does, we check for real | |
| 779 // templates separately from checking for patterns. | |
| 780 $files = drupal_system_listing($regex, $path, 'name', 0); | |
| 781 foreach ($files as $template => $file) { | |
| 782 // Ignore sub-theme templates for the current theme. | |
| 783 if (strpos($file->filename, str_replace($subtheme_paths, '', $file->filename)) !== 0) { | |
| 784 continue; | |
| 785 } | |
| 786 // Chop off the remaining extensions if there are any. $template already | |
| 787 // has the rightmost extension removed, but there might still be more, | |
| 788 // such as with .tpl.php, which still has .tpl in $template at this point. | |
| 789 if (($pos = strpos($template, '.')) !== FALSE) { | |
| 790 $template = substr($template, 0, $pos); | |
| 791 } | |
| 792 // Transform - in filenames to _ to match function naming scheme | |
| 793 // for the purposes of searching. | |
| 794 $hook = strtr($template, '-', '_'); | |
| 795 if (isset($cache[$hook])) { | |
| 796 $templates[$hook] = array( | |
| 797 'template' => $template, | |
| 798 'path' => dirname($file->filename), | |
| 799 ); | |
| 800 } | |
| 801 } | |
| 802 | |
| 803 $patterns = array_keys($files); | |
| 804 | |
| 805 foreach ($cache as $hook => $info) { | |
| 806 if (!empty($info['pattern'])) { | |
| 807 // Transform _ in pattern to - to match file naming scheme | |
| 808 // for the purposes of searching. | |
| 809 $pattern = strtr($info['pattern'], '_', '-'); | |
| 810 | |
| 811 $matches = preg_grep('/^'. $pattern .'/', $patterns); | |
| 812 if ($matches) { | |
| 813 foreach ($matches as $match) { | |
| 814 $file = substr($match, 0, strpos($match, '.')); | |
| 815 // Put the underscores back in for the hook name and register this pattern. | |
| 816 $templates[strtr($file, '-', '_')] = array( | |
| 817 'template' => $file, | |
| 818 'path' => dirname($files[$match]->filename), | |
| 819 'arguments' => $info['arguments'], | |
| 820 ); | |
| 821 } | |
| 822 } | |
| 823 } | |
| 824 } | |
| 825 return $templates; | |
| 826 } | |
| 827 | |
| 828 /** | |
| 829 * Retrieve an associative array containing the settings for a theme. | |
| 830 * | |
| 831 * The final settings are arrived at by merging the default settings, | |
| 832 * the site-wide settings, and the settings defined for the specific theme. | |
| 833 * If no $key was specified, only the site-wide theme defaults are retrieved. | |
| 834 * | |
| 835 * The default values for each of settings are also defined in this function. | |
| 836 * To add new settings, add their default values here, and then add form elements | |
| 837 * to system_theme_settings() in system.module. | |
| 838 * | |
| 839 * @param $key | |
| 840 * The template/style value for a given theme. | |
| 841 * | |
| 842 * @return | |
| 843 * An associative array containing theme settings. | |
| 844 */ | |
| 845 function theme_get_settings($key = NULL) { | |
| 846 $defaults = array( | |
| 847 'mission' => '', | |
| 848 'default_logo' => 1, | |
| 849 'logo_path' => '', | |
| 850 'default_favicon' => 1, | |
| 851 'favicon_path' => '', | |
| 852 'primary_links' => 1, | |
| 853 'secondary_links' => 1, | |
| 854 'toggle_logo' => 1, | |
| 855 'toggle_favicon' => 1, | |
| 856 'toggle_name' => 1, | |
| 857 'toggle_search' => 1, | |
| 858 'toggle_slogan' => 0, | |
| 859 'toggle_mission' => 1, | |
| 860 'toggle_node_user_picture' => 0, | |
| 861 'toggle_comment_user_picture' => 0, | |
| 862 'toggle_primary_links' => 1, | |
| 863 'toggle_secondary_links' => 1, | |
| 864 ); | |
| 865 | |
| 866 if (module_exists('node')) { | |
| 867 foreach (node_get_types() as $type => $name) { | |
| 868 $defaults['toggle_node_info_'. $type] = 1; | |
| 869 } | |
| 870 } | |
| 871 $settings = array_merge($defaults, variable_get('theme_settings', array())); | |
| 872 | |
| 873 if ($key) { | |
| 874 $settings = array_merge($settings, variable_get(str_replace('/', '_', 'theme_'. $key .'_settings'), array())); | |
| 875 } | |
| 876 | |
| 877 // Only offer search box if search.module is enabled. | |
| 878 if (!module_exists('search') || !user_access('search content')) { | |
| 879 $settings['toggle_search'] = 0; | |
| 880 } | |
| 881 | |
| 882 return $settings; | |
| 883 } | |
| 884 | |
| 885 /** | |
| 886 * Retrieve a setting for the current theme. | |
| 887 * This function is designed for use from within themes & engines | |
| 888 * to determine theme settings made in the admin interface. | |
| 889 * | |
| 890 * Caches values for speed (use $refresh = TRUE to refresh cache) | |
| 891 * | |
| 892 * @param $setting_name | |
| 893 * The name of the setting to be retrieved. | |
| 894 * | |
| 895 * @param $refresh | |
| 896 * Whether to reload the cache of settings. | |
| 897 * | |
| 898 * @return | |
| 899 * The value of the requested setting, NULL if the setting does not exist. | |
| 900 */ | |
| 901 function theme_get_setting($setting_name, $refresh = FALSE) { | |
| 902 global $theme_key; | |
| 903 static $settings; | |
| 904 | |
| 905 if (empty($settings) || $refresh) { | |
| 906 $settings = theme_get_settings($theme_key); | |
| 907 | |
| 908 $themes = list_themes(); | |
| 909 $theme_object = $themes[$theme_key]; | |
| 910 | |
| 911 if ($settings['mission'] == '') { | |
| 912 $settings['mission'] = variable_get('site_mission', ''); | |
| 913 } | |
| 914 | |
| 915 if (!$settings['toggle_mission']) { | |
| 916 $settings['mission'] = ''; | |
| 917 } | |
| 918 | |
| 919 if ($settings['toggle_logo']) { | |
| 920 if ($settings['default_logo']) { | |
| 921 $settings['logo'] = base_path() . dirname($theme_object->filename) .'/logo.png'; | |
| 922 } | |
| 923 elseif ($settings['logo_path']) { | |
| 924 $settings['logo'] = base_path() . $settings['logo_path']; | |
| 925 } | |
| 926 } | |
| 927 | |
| 928 if ($settings['toggle_favicon']) { | |
| 929 if ($settings['default_favicon']) { | |
| 930 if (file_exists($favicon = dirname($theme_object->filename) .'/favicon.ico')) { | |
| 931 $settings['favicon'] = base_path() . $favicon; | |
| 932 } | |
| 933 else { | |
| 934 $settings['favicon'] = base_path() .'misc/favicon.ico'; | |
| 935 } | |
| 936 } | |
| 937 elseif ($settings['favicon_path']) { | |
| 938 $settings['favicon'] = base_path() . $settings['favicon_path']; | |
| 939 } | |
| 940 else { | |
| 941 $settings['toggle_favicon'] = FALSE; | |
| 942 } | |
| 943 } | |
| 944 } | |
| 945 | |
| 946 return isset($settings[$setting_name]) ? $settings[$setting_name] : NULL; | |
| 947 } | |
| 948 | |
| 949 /** | |
| 950 * Render a system default template, which is essentially a PHP template. | |
| 951 * | |
| 952 * @param $file | |
| 953 * The filename of the template to render. | |
| 954 * @param $variables | |
| 955 * A keyed array of variables that will appear in the output. | |
| 956 * | |
| 957 * @return | |
| 958 * The output generated by the template. | |
| 959 */ | |
| 960 function theme_render_template($file, $variables) { | |
| 961 extract($variables, EXTR_SKIP); // Extract the variables to a local namespace | |
| 962 ob_start(); // Start output buffering | |
| 963 include "./$file"; // Include the file | |
| 964 $contents = ob_get_contents(); // Get the contents of the buffer | |
| 965 ob_end_clean(); // End buffering and discard | |
| 966 return $contents; // Return the contents | |
| 967 } | |
| 968 | |
| 969 /** | |
| 970 * @defgroup themeable Default theme implementations | |
| 971 * @{ | |
| 972 * Functions and templates that present output to the user, and can be | |
| 973 * implemented by themes. | |
| 974 * | |
| 975 * Drupal's presentation layer is a pluggable system known as the theme | |
| 976 * layer. Each theme can take control over most of Drupal's output, and | |
| 977 * has complete control over the CSS. | |
| 978 * | |
| 979 * Inside Drupal, the theme layer is utilized by the use of the theme() | |
| 980 * function, which is passed the name of a component (the theme hook) | |
| 981 * and several arguments. For example, theme('table', $header, $rows); | |
| 982 * Additionally, the theme() function can take an array of theme | |
| 983 * hooks, which can be used to provide 'fallback' implementations to | |
| 984 * allow for more specific control of output. For example, the function: | |
| 985 * theme(array('table__foo', 'table'), $header, $rows) would look to see if | |
| 986 * 'table__foo' is registered anywhere; if it is not, it would 'fall back' | |
| 987 * to the generic 'table' implementation. This can be used to attach specific | |
| 988 * theme functions to named objects, allowing the themer more control over | |
| 989 * specific types of output. | |
| 990 * | |
| 991 * As of Drupal 6, every theme hook is required to be registered by the | |
| 992 * module that owns it, so that Drupal can tell what to do with it and | |
| 993 * to make it simple for themes to identify and override the behavior | |
| 994 * for these calls. | |
| 995 * | |
| 996 * The theme hooks are registered via hook_theme(), which returns an | |
| 997 * array of arrays with information about the hook. It describes the | |
| 998 * arguments the function or template will need, and provides | |
| 999 * defaults for the template in case they are not filled in. If the default | |
| 1000 * implementation is a function, by convention it is named theme_HOOK(). | |
| 1001 * | |
| 1002 * Each module should provide a default implementation for themes that | |
| 1003 * it registers. This implementation may be either a function or a template; | |
| 1004 * if it is a function it must be specified via hook_theme(). By convention, | |
| 1005 * default implementations of theme hooks are named theme_HOOK. Default | |
| 1006 * template implementations are stored in the module directory. | |
| 1007 * | |
| 1008 * Drupal's default template renderer is a simple PHP parsing engine that | |
| 1009 * includes the template and stores the output. Drupal's theme engines | |
| 1010 * can provide alternate template engines, such as XTemplate, Smarty and | |
| 1011 * PHPTal. The most common template engine is PHPTemplate (included with | |
| 1012 * Drupal and implemented in phptemplate.engine, which uses Drupal's default | |
| 1013 * template renderer. | |
| 1014 * | |
| 1015 * In order to create theme-specific implementations of these hooks, | |
| 1016 * themes can implement their own version of theme hooks, either as functions | |
| 1017 * or templates. These implementations will be used instead of the default | |
| 1018 * implementation. If using a pure .theme without an engine, the .theme is | |
| 1019 * required to implement its own version of hook_theme() to tell Drupal what | |
| 1020 * it is implementing; themes utilizing an engine will have their well-named | |
| 1021 * theming functions automatically registered for them. While this can vary | |
| 1022 * based upon the theme engine, the standard set by phptemplate is that theme | |
| 1023 * functions should be named either phptemplate_HOOK or THEMENAME_HOOK. For | |
| 1024 * example, for Drupal's default theme (Garland) to implement the 'table' hook, | |
| 1025 * the phptemplate.engine would find phptemplate_table() or garland_table(). | |
| 1026 * The ENGINE_HOOK() syntax is preferred, as this can be used by sub-themes | |
| 1027 * (which are themes that share code but use different stylesheets). | |
| 1028 * | |
| 1029 * The theme system is described and defined in theme.inc. | |
| 1030 * | |
| 1031 * @see theme() | |
| 1032 * @see hook_theme() | |
| 1033 */ | |
| 1034 | |
| 1035 /** | |
| 1036 * Formats text for emphasized display in a placeholder inside a sentence. | |
| 1037 * Used automatically by t(). | |
| 1038 * | |
| 1039 * @param $text | |
| 1040 * The text to format (plain-text). | |
| 1041 * @return | |
| 1042 * The formatted text (html). | |
| 1043 */ | |
| 1044 function theme_placeholder($text) { | |
| 1045 return '<em>'. check_plain($text) .'</em>'; | |
| 1046 } | |
| 1047 | |
| 1048 /** | |
| 1049 * Return a themed set of status and/or error messages. The messages are grouped | |
| 1050 * by type. | |
| 1051 * | |
| 1052 * @param $display | |
| 1053 * (optional) Set to 'status' or 'error' to display only messages of that type. | |
| 1054 * | |
| 1055 * @return | |
| 1056 * A string containing the messages. | |
| 1057 */ | |
| 1058 function theme_status_messages($display = NULL) { | |
| 1059 $output = ''; | |
| 1060 foreach (drupal_get_messages($display) as $type => $messages) { | |
| 1061 $output .= "<div class=\"messages $type\">\n"; | |
| 1062 if (count($messages) > 1) { | |
| 1063 $output .= " <ul>\n"; | |
| 1064 foreach ($messages as $message) { | |
| 1065 $output .= ' <li>'. $message ."</li>\n"; | |
| 1066 } | |
| 1067 $output .= " </ul>\n"; | |
| 1068 } | |
| 1069 else { | |
| 1070 $output .= $messages[0]; | |
| 1071 } | |
| 1072 $output .= "</div>\n"; | |
| 1073 } | |
| 1074 return $output; | |
| 1075 } | |
| 1076 | |
| 1077 /** | |
| 1078 * Return a themed set of links. | |
| 1079 * | |
| 1080 * @param $links | |
| 1081 * A keyed array of links to be themed. | |
| 1082 * @param $attributes | |
| 1083 * A keyed array of attributes | |
| 1084 * @return | |
| 1085 * A string containing an unordered list of links. | |
| 1086 */ | |
| 1087 function theme_links($links, $attributes = array('class' => 'links')) { | |
| 1088 $output = ''; | |
| 1089 | |
| 1090 if (count($links) > 0) { | |
| 1091 $output = '<ul'. drupal_attributes($attributes) .'>'; | |
| 1092 | |
| 1093 $num_links = count($links); | |
| 1094 $i = 1; | |
| 1095 | |
| 1096 foreach ($links as $key => $link) { | |
| 1097 $class = $key; | |
| 1098 | |
| 1099 // Add first, last and active classes to the list of links to help out themers. | |
| 1100 if ($i == 1) { | |
| 1101 $class .= ' first'; | |
| 1102 } | |
| 1103 if ($i == $num_links) { | |
| 1104 $class .= ' last'; | |
| 1105 } | |
| 1106 if (isset($link['href']) && $link['href'] == $_GET['q']) { | |
| 1107 $class .= ' active'; | |
| 1108 } | |
| 1109 $output .= '<li class="'. $class .'">'; | |
| 1110 | |
| 1111 if (isset($link['href'])) { | |
| 1112 // Pass in $link as $options, they share the same keys. | |
| 1113 $output .= l($link['title'], $link['href'], $link); | |
| 1114 } | |
| 1115 else if (!empty($link['title'])) { | |
| 1116 // Some links are actually not links, but we wrap these in <span> for adding title and class attributes | |
| 1117 if (empty($link['html'])) { | |
| 1118 $link['title'] = check_plain($link['title']); | |
| 1119 } | |
| 1120 $span_attributes = ''; | |
| 1121 if (isset($link['attributes'])) { | |
| 1122 $span_attributes = drupal_attributes($link['attributes']); | |
| 1123 } | |
| 1124 $output .= '<span'. $span_attributes .'>'. $link['title'] .'</span>'; | |
| 1125 } | |
| 1126 | |
| 1127 $i++; | |
| 1128 $output .= "</li>\n"; | |
| 1129 } | |
| 1130 | |
| 1131 $output .= '</ul>'; | |
| 1132 } | |
| 1133 | |
| 1134 return $output; | |
| 1135 } | |
| 1136 | |
| 1137 /** | |
| 1138 * Return a themed image. | |
| 1139 * | |
| 1140 * @param $path | |
| 1141 * Either the path of the image file (relative to base_path()) or a full URL. | |
| 1142 * @param $alt | |
| 1143 * The alternative text for text-based browsers. | |
| 1144 * @param $title | |
| 1145 * The title text is displayed when the image is hovered in some popular browsers. | |
| 1146 * @param $attributes | |
| 1147 * Associative array of attributes to be placed in the img tag. | |
| 1148 * @param $getsize | |
| 1149 * If set to TRUE, the image's dimension are fetched and added as width/height attributes. | |
| 1150 * @return | |
| 1151 * A string containing the image tag. | |
| 1152 */ | |
| 1153 function theme_image($path, $alt = '', $title = '', $attributes = NULL, $getsize = TRUE) { | |
| 1154 if (!$getsize || (is_file($path) && (list($width, $height, $type, $image_attributes) = @getimagesize($path)))) { | |
| 1155 $attributes = drupal_attributes($attributes); | |
| 1156 $url = (url($path) == $path) ? $path : (base_path() . $path); | |
| 1157 return '<img src="'. check_url($url) .'" alt="'. check_plain($alt) .'" title="'. check_plain($title) .'" '. (isset($image_attributes) ? $image_attributes : '') . $attributes .' />'; | |
| 1158 } | |
| 1159 } | |
| 1160 | |
| 1161 /** | |
| 1162 * Return a themed breadcrumb trail. | |
| 1163 * | |
| 1164 * @param $breadcrumb | |
| 1165 * An array containing the breadcrumb links. | |
| 1166 * @return a string containing the breadcrumb output. | |
| 1167 */ | |
| 1168 function theme_breadcrumb($breadcrumb) { | |
| 1169 if (!empty($breadcrumb)) { | |
| 1170 return '<div class="breadcrumb">'. implode(' » ', $breadcrumb) .'</div>'; | |
| 1171 } | |
| 1172 } | |
| 1173 | |
| 1174 /** | |
| 1175 * Return a themed help message. | |
| 1176 * | |
| 1177 * @return a string containing the helptext for the current page. | |
| 1178 */ | |
| 1179 function theme_help() { | |
| 1180 if ($help = menu_get_active_help()) { | |
| 1181 return '<div class="help">'. $help .'</div>'; | |
| 1182 } | |
| 1183 } | |
| 1184 | |
| 1185 /** | |
| 1186 * Return a themed submenu, typically displayed under the tabs. | |
| 1187 * | |
| 1188 * @param $links | |
| 1189 * An array of links. | |
| 1190 */ | |
| 1191 function theme_submenu($links) { | |
| 1192 return '<div class="submenu">'. implode(' | ', $links) .'</div>'; | |
| 1193 } | |
| 1194 | |
| 1195 /** | |
| 1196 * Return a themed table. | |
| 1197 * | |
| 1198 * @param $header | |
| 1199 * An array containing the table headers. Each element of the array can be | |
| 1200 * either a localized string or an associative array with the following keys: | |
| 1201 * - "data": The localized title of the table column. | |
| 1202 * - "field": The database field represented in the table column (required if | |
| 1203 * user is to be able to sort on this column). | |
| 1204 * - "sort": A default sort order for this column ("asc" or "desc"). | |
| 1205 * - Any HTML attributes, such as "colspan", to apply to the column header cell. | |
| 1206 * @param $rows | |
| 1207 * An array of table rows. Every row is an array of cells, or an associative | |
| 1208 * array with the following keys: | |
| 1209 * - "data": an array of cells | |
| 1210 * - Any HTML attributes, such as "class", to apply to the table row. | |
| 1211 * | |
| 1212 * Each cell can be either a string or an associative array with the following keys: | |
| 1213 * - "data": The string to display in the table cell. | |
| 1214 * - "header": Indicates this cell is a header. | |
| 1215 * - Any HTML attributes, such as "colspan", to apply to the table cell. | |
| 1216 * | |
| 1217 * Here's an example for $rows: | |
| 1218 * @verbatim | |
| 1219 * $rows = array( | |
| 1220 * // Simple row | |
| 1221 * array( | |
| 1222 * 'Cell 1', 'Cell 2', 'Cell 3' | |
| 1223 * ), | |
| 1224 * // Row with attributes on the row and some of its cells. | |
| 1225 * array( | |
| 1226 * 'data' => array('Cell 1', array('data' => 'Cell 2', 'colspan' => 2)), 'class' => 'funky' | |
| 1227 * ) | |
| 1228 * ); | |
| 1229 * @endverbatim | |
| 1230 * | |
| 1231 * @param $attributes | |
| 1232 * An array of HTML attributes to apply to the table tag. | |
| 1233 * @param $caption | |
| 1234 * A localized string to use for the <caption> tag. | |
| 1235 * @return | |
| 1236 * An HTML string representing the table. | |
| 1237 */ | |
| 1238 function theme_table($header, $rows, $attributes = array(), $caption = NULL) { | |
| 1239 | |
| 1240 // Add sticky headers, if applicable. | |
| 1241 if (count($header)) { | |
| 1242 drupal_add_js('misc/tableheader.js'); | |
| 1243 // Add 'sticky-enabled' class to the table to identify it for JS. | |
| 1244 // This is needed to target tables constructed by this function. | |
| 1245 $attributes['class'] = empty($attributes['class']) ? 'sticky-enabled' : ($attributes['class'] .' sticky-enabled'); | |
| 1246 } | |
| 1247 | |
| 1248 $output = '<table'. drupal_attributes($attributes) .">\n"; | |
| 1249 | |
| 1250 if (isset($caption)) { | |
| 1251 $output .= '<caption>'. $caption ."</caption>\n"; | |
| 1252 } | |
| 1253 | |
| 1254 // Format the table header: | |
| 1255 if (count($header)) { | |
| 1256 $ts = tablesort_init($header); | |
| 1257 // HTML requires that the thead tag has tr tags in it follwed by tbody | |
| 1258 // tags. Using ternary operator to check and see if we have any rows. | |
| 1259 $output .= (count($rows) ? ' <thead><tr>' : ' <tr>'); | |
| 1260 foreach ($header as $cell) { | |
| 1261 $cell = tablesort_header($cell, $header, $ts); | |
| 1262 $output .= _theme_table_cell($cell, TRUE); | |
| 1263 } | |
| 1264 // Using ternary operator to close the tags based on whether or not there are rows | |
| 1265 $output .= (count($rows) ? " </tr></thead>\n" : "</tr>\n"); | |
| 1266 } | |
| 1267 else { | |
| 1268 $ts = array(); | |
| 1269 } | |
| 1270 | |
| 1271 // Format the table rows: | |
| 1272 if (count($rows)) { | |
| 1273 $output .= "<tbody>\n"; | |
| 1274 $flip = array('even' => 'odd', 'odd' => 'even'); | |
| 1275 $class = 'even'; | |
| 1276 foreach ($rows as $number => $row) { | |
| 1277 $attributes = array(); | |
| 1278 | |
| 1279 // Check if we're dealing with a simple or complex row | |
| 1280 if (isset($row['data'])) { | |
| 1281 foreach ($row as $key => $value) { | |
| 1282 if ($key == 'data') { | |
| 1283 $cells = $value; | |
| 1284 } | |
| 1285 else { | |
| 1286 $attributes[$key] = $value; | |
| 1287 } | |
| 1288 } | |
| 1289 } | |
| 1290 else { | |
| 1291 $cells = $row; | |
| 1292 } | |
| 1293 if (count($cells)) { | |
| 1294 // Add odd/even class | |
| 1295 $class = $flip[$class]; | |
| 1296 if (isset($attributes['class'])) { | |
| 1297 $attributes['class'] .= ' '. $class; | |
| 1298 } | |
| 1299 else { | |
| 1300 $attributes['class'] = $class; | |
| 1301 } | |
| 1302 | |
| 1303 // Build row | |
| 1304 $output .= ' <tr'. drupal_attributes($attributes) .'>'; | |
| 1305 $i = 0; | |
| 1306 foreach ($cells as $cell) { | |
| 1307 $cell = tablesort_cell($cell, $header, $ts, $i++); | |
| 1308 $output .= _theme_table_cell($cell); | |
| 1309 } | |
| 1310 $output .= " </tr>\n"; | |
| 1311 } | |
| 1312 } | |
| 1313 $output .= "</tbody>\n"; | |
| 1314 } | |
| 1315 | |
| 1316 $output .= "</table>\n"; | |
| 1317 return $output; | |
| 1318 } | |
| 1319 | |
| 1320 /** | |
| 1321 * Returns a header cell for tables that have a select all functionality. | |
| 1322 */ | |
| 1323 function theme_table_select_header_cell() { | |
| 1324 drupal_add_js('misc/tableselect.js'); | |
| 1325 | |
| 1326 return array('class' => 'select-all'); | |
| 1327 } | |
| 1328 | |
| 1329 /** | |
| 1330 * Return a themed sort icon. | |
| 1331 * | |
| 1332 * @param $style | |
| 1333 * Set to either asc or desc. This sets which icon to show. | |
| 1334 * @return | |
| 1335 * A themed sort icon. | |
| 1336 */ | |
| 1337 function theme_tablesort_indicator($style) { | |
| 1338 if ($style == "asc") { | |
| 1339 return theme('image', 'misc/arrow-asc.png', t('sort icon'), t('sort ascending')); | |
| 1340 } | |
| 1341 else { | |
| 1342 return theme('image', 'misc/arrow-desc.png', t('sort icon'), t('sort descending')); | |
| 1343 } | |
| 1344 } | |
| 1345 | |
| 1346 /** | |
| 1347 * Return a themed box. | |
| 1348 * | |
| 1349 * @param $title | |
| 1350 * The subject of the box. | |
| 1351 * @param $content | |
| 1352 * The content of the box. | |
| 1353 * @param $region | |
| 1354 * The region in which the box is displayed. | |
| 1355 * @return | |
| 1356 * A string containing the box output. | |
| 1357 */ | |
| 1358 function theme_box($title, $content, $region = 'main') { | |
| 1359 $output = '<h2 class="title">'. $title .'</h2><div>'. $content .'</div>'; | |
| 1360 return $output; | |
| 1361 } | |
| 1362 | |
| 1363 /** | |
| 1364 * Return a themed marker, useful for marking new or updated | |
| 1365 * content. | |
| 1366 * | |
| 1367 * @param $type | |
| 1368 * Number representing the marker type to display | |
| 1369 * @see MARK_NEW, MARK_UPDATED, MARK_READ | |
| 1370 * @return | |
| 1371 * A string containing the marker. | |
| 1372 */ | |
| 1373 function theme_mark($type = MARK_NEW) { | |
| 1374 global $user; | |
| 1375 if ($user->uid) { | |
| 1376 if ($type == MARK_NEW) { | |
| 1377 return ' <span class="marker">'. t('new') .'</span>'; | |
| 1378 } | |
| 1379 else if ($type == MARK_UPDATED) { | |
| 1380 return ' <span class="marker">'. t('updated') .'</span>'; | |
| 1381 } | |
| 1382 } | |
| 1383 } | |
| 1384 | |
| 1385 /** | |
| 1386 * Return a themed list of items. | |
| 1387 * | |
| 1388 * @param $items | |
| 1389 * An array of items to be displayed in the list. If an item is a string, | |
| 1390 * then it is used as is. If an item is an array, then the "data" element of | |
| 1391 * the array is used as the contents of the list item. If an item is an array | |
| 1392 * with a "children" element, those children are displayed in a nested list. | |
| 1393 * All other elements are treated as attributes of the list item element. | |
| 1394 * @param $title | |
| 1395 * The title of the list. | |
| 1396 * @param $attributes | |
| 1397 * The attributes applied to the list element. | |
| 1398 * @param $type | |
| 1399 * The type of list to return (e.g. "ul", "ol") | |
| 1400 * @return | |
| 1401 * A string containing the list output. | |
| 1402 */ | |
| 1403 function theme_item_list($items = array(), $title = NULL, $type = 'ul', $attributes = NULL) { | |
| 1404 $output = '<div class="item-list">'; | |
| 1405 if (isset($title)) { | |
| 1406 $output .= '<h3>'. $title .'</h3>'; | |
| 1407 } | |
| 1408 | |
| 1409 if (!empty($items)) { | |
| 1410 $output .= "<$type". drupal_attributes($attributes) .'>'; | |
| 1411 $num_items = count($items); | |
| 1412 foreach ($items as $i => $item) { | |
| 1413 $attributes = array(); | |
| 1414 $children = array(); | |
| 1415 if (is_array($item)) { | |
| 1416 foreach ($item as $key => $value) { | |
| 1417 if ($key == 'data') { | |
| 1418 $data = $value; | |
| 1419 } | |
| 1420 elseif ($key == 'children') { | |
| 1421 $children = $value; | |
| 1422 } | |
| 1423 else { | |
| 1424 $attributes[$key] = $value; | |
| 1425 } | |
| 1426 } | |
| 1427 } | |
| 1428 else { | |
| 1429 $data = $item; | |
| 1430 } | |
| 1431 if (count($children) > 0) { | |
| 1432 $data .= theme_item_list($children, NULL, $type, $attributes); // Render nested list | |
| 1433 } | |
| 1434 if ($i == 0) { | |
| 1435 $attributes['class'] = empty($attributes['class']) ? 'first' : ($attributes['class'] .' first'); | |
| 1436 } | |
| 1437 if ($i == $num_items - 1) { | |
| 1438 $attributes['class'] = empty($attributes['class']) ? 'last' : ($attributes['class'] .' last'); | |
| 1439 } | |
| 1440 $output .= '<li'. drupal_attributes($attributes) .'>'. $data ."</li>\n"; | |
| 1441 } | |
| 1442 $output .= "</$type>"; | |
| 1443 } | |
| 1444 $output .= '</div>'; | |
| 1445 return $output; | |
| 1446 } | |
| 1447 | |
| 1448 /** | |
| 1449 * Returns code that emits the 'more help'-link. | |
| 1450 */ | |
| 1451 function theme_more_help_link($url) { | |
| 1452 return '<div class="more-help-link">'. t('[<a href="@link">more help...</a>]', array('@link' => check_url($url))) .'</div>'; | |
| 1453 } | |
| 1454 | |
| 1455 /** | |
| 1456 * Return code that emits an XML icon. | |
| 1457 * | |
| 1458 * For most use cases, this function has been superseded by theme_feed_icon(). | |
| 1459 * | |
| 1460 * @see theme_feed_icon() | |
| 1461 * @param $url | |
| 1462 * The url of the feed. | |
| 1463 */ | |
| 1464 function theme_xml_icon($url) { | |
| 1465 if ($image = theme('image', 'misc/xml.png', t('XML feed'), t('XML feed'))) { | |
| 1466 return '<a href="'. check_url($url) .'" class="xml-icon">'. $image .'</a>'; | |
| 1467 } | |
| 1468 } | |
| 1469 | |
| 1470 /** | |
| 1471 * Return code that emits an feed icon. | |
| 1472 * | |
| 1473 * @param $url | |
| 1474 * The url of the feed. | |
| 1475 * @param $title | |
| 1476 * A descriptive title of the feed. | |
| 1477 */ | |
| 1478 function theme_feed_icon($url, $title) { | |
| 1479 if ($image = theme('image', 'misc/feed.png', t('Syndicate content'), $title)) { | |
| 1480 return '<a href="'. check_url($url) .'" class="feed-icon">'. $image .'</a>'; | |
| 1481 } | |
| 1482 } | |
| 1483 | |
| 1484 /** | |
| 1485 * Returns code that emits the 'more' link used on blocks. | |
| 1486 * | |
| 1487 * @param $url | |
| 1488 * The url of the main page | |
| 1489 * @param $title | |
| 1490 * A descriptive verb for the link, like 'Read more' | |
| 1491 */ | |
| 1492 function theme_more_link($url, $title) { | |
| 1493 return '<div class="more-link">'. t('<a href="@link" title="@title">more</a>', array('@link' => check_url($url), '@title' => $title)) .'</div>'; | |
| 1494 } | |
| 1495 | |
| 1496 /** | |
| 1497 * Execute hook_footer() which is run at the end of the page right before the | |
| 1498 * close of the body tag. | |
| 1499 * | |
| 1500 * @param $main (optional) | |
| 1501 * Whether the current page is the front page of the site. | |
| 1502 * @return | |
| 1503 * A string containing the results of the hook_footer() calls. | |
| 1504 */ | |
| 1505 function theme_closure($main = 0) { | |
| 1506 $footer = module_invoke_all('footer', $main); | |
| 1507 return implode("\n", $footer) . drupal_get_js('footer'); | |
| 1508 } | |
| 1509 | |
| 1510 /** | |
| 1511 * Return a set of blocks available for the current user. | |
| 1512 * | |
| 1513 * @param $region | |
| 1514 * Which set of blocks to retrieve. | |
| 1515 * @return | |
| 1516 * A string containing the themed blocks for this region. | |
| 1517 */ | |
| 1518 function theme_blocks($region) { | |
| 1519 $output = ''; | |
| 1520 | |
| 1521 if ($list = block_list($region)) { | |
| 1522 foreach ($list as $key => $block) { | |
| 1523 // $key == <i>module</i>_<i>delta</i> | |
| 1524 $output .= theme('block', $block); | |
| 1525 } | |
| 1526 } | |
| 1527 | |
| 1528 // Add any content assigned to this region through drupal_set_content() calls. | |
| 1529 $output .= drupal_get_content($region); | |
| 1530 | |
| 1531 return $output; | |
| 1532 } | |
| 1533 | |
| 1534 /** | |
| 1535 * Format a username. | |
| 1536 * | |
| 1537 * @param $object | |
| 1538 * The user object to format, usually returned from user_load(). | |
| 1539 * @return | |
| 1540 * A string containing an HTML link to the user's page if the passed object | |
| 1541 * suggests that this is a site user. Otherwise, only the username is returned. | |
| 1542 */ | |
| 1543 function theme_username($object) { | |
| 1544 | |
| 1545 if ($object->uid && $object->name) { | |
| 1546 // Shorten the name when it is too long or it will break many tables. | |
| 1547 if (drupal_strlen($object->name) > 20) { | |
| 1548 $name = drupal_substr($object->name, 0, 15) .'...'; | |
| 1549 } | |
| 1550 else { | |
| 1551 $name = $object->name; | |
| 1552 } | |
| 1553 | |
| 1554 if (user_access('access user profiles')) { | |
| 1555 $output = l($name, 'user/'. $object->uid, array('title' => t('View user profile.'))); | |
| 1556 } | |
| 1557 else { | |
| 1558 $output = check_plain($name); | |
| 1559 } | |
| 1560 } | |
| 1561 else if ($object->name) { | |
| 1562 // Sometimes modules display content composed by people who are | |
| 1563 // not registered members of the site (e.g. mailing list or news | |
| 1564 // aggregator modules). This clause enables modules to display | |
| 1565 // the true author of the content. | |
| 1566 if (!empty($object->homepage)) { | |
| 1567 $output = l($object->name, $object->homepage, array('rel' => 'nofollow')); | |
| 1568 } | |
| 1569 else { | |
| 1570 $output = check_plain($object->name); | |
| 1571 } | |
| 1572 | |
| 1573 $output .= ' ('. t('not verified') .')'; | |
| 1574 } | |
| 1575 else { | |
| 1576 $output = variable_get('anonymous', t('Anonymous')); | |
| 1577 } | |
| 1578 | |
| 1579 return $output; | |
| 1580 } | |
| 1581 | |
| 1582 /** | |
| 1583 * Return a themed progress bar. | |
| 1584 * | |
| 1585 * @param $percent | |
| 1586 * The percentage of the progress. | |
| 1587 * @param $message | |
| 1588 * A string containing information to be displayed. | |
| 1589 * @return | |
| 1590 * A themed HTML string representing the progress bar. | |
| 1591 */ | |
| 1592 function theme_progress_bar($percent, $message) { | |
| 1593 $output = '<div id="progress" class="progress">'; | |
| 1594 $output .= '<div class="bar"><div class="filled" style="width: '. $percent .'%"></div></div>'; | |
| 1595 $output .= '<div class="percentage">'. $percent .'%</div>'; | |
| 1596 $output .= '<div class="message">'. $message .'</div>'; | |
| 1597 $output .= '</div>'; | |
| 1598 | |
| 1599 return $output; | |
| 1600 } | |
| 1601 | |
| 1602 /** | |
| 1603 * Create a standard indentation div. Used for drag and drop tables. | |
| 1604 * | |
| 1605 * @param $size | |
| 1606 * Optional. The number of indentations to create. | |
| 1607 * @return | |
| 1608 * A string containing indentations. | |
| 1609 */ | |
| 1610 function theme_indentation($size = 1) { | |
| 1611 $output = ''; | |
| 1612 for ($n = 0; $n < $size; $n++) { | |
| 1613 $output .= '<div class="indentation"> </div>'; | |
| 1614 } | |
| 1615 return $output; | |
| 1616 } | |
| 1617 | |
| 1618 /** | |
| 1619 * @} End of "defgroup themeable". | |
| 1620 */ | |
| 1621 | |
| 1622 function _theme_table_cell($cell, $header = FALSE) { | |
| 1623 $attributes = ''; | |
| 1624 | |
| 1625 if (is_array($cell)) { | |
| 1626 $data = isset($cell['data']) ? $cell['data'] : ''; | |
| 1627 $header |= isset($cell['header']); | |
| 1628 unset($cell['data']); | |
| 1629 unset($cell['header']); | |
| 1630 $attributes = drupal_attributes($cell); | |
| 1631 } | |
| 1632 else { | |
| 1633 $data = $cell; | |
| 1634 } | |
| 1635 | |
| 1636 if ($header) { | |
| 1637 $output = "<th$attributes>$data</th>"; | |
| 1638 } | |
| 1639 else { | |
| 1640 $output = "<td$attributes>$data</td>"; | |
| 1641 } | |
| 1642 | |
| 1643 return $output; | |
| 1644 } | |
| 1645 | |
| 1646 /** | |
| 1647 * Adds a default set of helper variables for preprocess functions and | |
| 1648 * templates. This comes in before any other preprocess function which makes | |
| 1649 * it possible to be used in default theme implementations (non-overriden | |
| 1650 * theme functions). | |
| 1651 */ | |
| 1652 function template_preprocess(&$variables, $hook) { | |
| 1653 global $user; | |
| 1654 static $count = array(); | |
| 1655 | |
| 1656 // Track run count for each hook to provide zebra striping. | |
| 1657 // See "template_preprocess_block()" which provides the same feature specific to blocks. | |
| 1658 $count[$hook] = isset($count[$hook]) && is_int($count[$hook]) ? $count[$hook] : 1; | |
| 1659 $variables['zebra'] = ($count[$hook] % 2) ? 'odd' : 'even'; | |
| 1660 $variables['id'] = $count[$hook]++; | |
| 1661 | |
| 1662 // Tell all templates where they are located. | |
| 1663 $variables['directory'] = path_to_theme(); | |
| 1664 | |
| 1665 // Set default variables that depend on the database. | |
| 1666 $variables['is_admin'] = FALSE; | |
| 1667 $variables['is_front'] = FALSE; | |
| 1668 $variables['logged_in'] = FALSE; | |
| 1669 if ($variables['db_is_active'] = db_is_active() && !defined('MAINTENANCE_MODE')) { | |
| 1670 // Check for administrators. | |
| 1671 if (user_access('access administration pages')) { | |
| 1672 $variables['is_admin'] = TRUE; | |
| 1673 } | |
| 1674 // Flag front page status. | |
| 1675 $variables['is_front'] = drupal_is_front_page(); | |
| 1676 // Tell all templates by which kind of user they're viewed. | |
| 1677 $variables['logged_in'] = ($user->uid > 0); | |
| 1678 // Provide user object to all templates | |
| 1679 $variables['user'] = $user; | |
| 1680 } | |
| 1681 } | |
| 1682 | |
| 1683 /** | |
| 1684 * Process variables for page.tpl.php | |
| 1685 * | |
| 1686 * Most themes utilize their own copy of page.tpl.php. The default is located | |
| 1687 * inside "modules/system/page.tpl.php". Look in there for the full list of | |
| 1688 * variables. | |
| 1689 * | |
| 1690 * Uses the arg() function to generate a series of page template suggestions | |
| 1691 * based on the current path. | |
| 1692 * | |
| 1693 * Any changes to variables in this preprocessor should also be changed inside | |
| 1694 * template_preprocess_maintenance_page() to keep all them consistent. | |
| 1695 * | |
| 1696 * The $variables array contains the following arguments: | |
| 1697 * - $content | |
| 1698 * - $show_blocks | |
| 1699 * | |
| 1700 * @see page.tpl.php | |
| 1701 */ | |
| 1702 function template_preprocess_page(&$variables) { | |
| 1703 // Add favicon | |
| 1704 if (theme_get_setting('toggle_favicon')) { | |
| 1705 drupal_set_html_head('<link rel="shortcut icon" href="'. check_url(theme_get_setting('favicon')) .'" type="image/x-icon" />'); | |
| 1706 } | |
| 1707 | |
| 1708 global $theme; | |
| 1709 // Populate all block regions. | |
| 1710 $regions = system_region_list($theme); | |
| 1711 // Load all region content assigned via blocks. | |
| 1712 foreach (array_keys($regions) as $region) { | |
| 1713 // Prevent left and right regions from rendering blocks when 'show_blocks' == FALSE. | |
| 1714 if (!(!$variables['show_blocks'] && ($region == 'left' || $region == 'right'))) { | |
| 1715 $blocks = theme('blocks', $region); | |
| 1716 } | |
| 1717 else { | |
| 1718 $blocks = ''; | |
| 1719 } | |
| 1720 // Assign region to a region variable. | |
| 1721 isset($variables[$region]) ? $variables[$region] .= $blocks : $variables[$region] = $blocks; | |
| 1722 } | |
| 1723 | |
| 1724 // Set up layout variable. | |
| 1725 $variables['layout'] = 'none'; | |
| 1726 if (!empty($variables['left'])) { | |
| 1727 $variables['layout'] = 'left'; | |
| 1728 } | |
| 1729 if (!empty($variables['right'])) { | |
| 1730 $variables['layout'] = ($variables['layout'] == 'left') ? 'both' : 'right'; | |
| 1731 } | |
| 1732 | |
| 1733 // Set mission when viewing the frontpage. | |
| 1734 if (drupal_is_front_page()) { | |
| 1735 $mission = filter_xss_admin(theme_get_setting('mission')); | |
| 1736 } | |
| 1737 | |
| 1738 // Construct page title | |
| 1739 if (drupal_get_title()) { | |
| 1740 $head_title = array(strip_tags(drupal_get_title()), variable_get('site_name', 'Drupal')); | |
| 1741 } | |
| 1742 else { | |
| 1743 $head_title = array(variable_get('site_name', 'Drupal')); | |
| 1744 if (variable_get('site_slogan', '')) { | |
| 1745 $head_title[] = variable_get('site_slogan', ''); | |
| 1746 } | |
| 1747 } | |
| 1748 $variables['head_title'] = implode(' | ', $head_title); | |
| 1749 $variables['base_path'] = base_path(); | |
| 1750 $variables['front_page'] = url(); | |
| 1751 $variables['breadcrumb'] = theme('breadcrumb', drupal_get_breadcrumb()); | |
| 1752 $variables['feed_icons'] = drupal_get_feeds(); | |
| 1753 $variables['footer_message'] = filter_xss_admin(variable_get('site_footer', FALSE)); | |
| 1754 $variables['head'] = drupal_get_html_head(); | |
| 1755 $variables['help'] = theme('help'); | |
| 1756 $variables['language'] = $GLOBALS['language']; | |
| 1757 $variables['language']->dir = $GLOBALS['language']->direction ? 'rtl' : 'ltr'; | |
| 1758 $variables['logo'] = theme_get_setting('logo'); | |
| 1759 $variables['messages'] = $variables['show_messages'] ? theme('status_messages') : ''; | |
| 1760 $variables['mission'] = isset($mission) ? $mission : ''; | |
| 1761 $variables['primary_links'] = theme_get_setting('toggle_primary_links') ? menu_primary_links() : array(); | |
| 1762 $variables['secondary_links'] = theme_get_setting('toggle_secondary_links') ? menu_secondary_links() : array(); | |
| 1763 $variables['search_box'] = (theme_get_setting('toggle_search') ? drupal_get_form('search_theme_form') : ''); | |
| 1764 $variables['site_name'] = (theme_get_setting('toggle_name') ? variable_get('site_name', 'Drupal') : ''); | |
| 1765 $variables['site_slogan'] = (theme_get_setting('toggle_slogan') ? variable_get('site_slogan', '') : ''); | |
| 1766 $variables['css'] = drupal_add_css(); | |
| 1767 $variables['styles'] = drupal_get_css(); | |
| 1768 $variables['scripts'] = drupal_get_js(); | |
| 1769 $variables['tabs'] = theme('menu_local_tasks'); | |
| 1770 $variables['title'] = drupal_get_title(); | |
| 1771 // Closure should be filled last. | |
| 1772 $variables['closure'] = theme('closure'); | |
| 1773 | |
| 1774 if ($node = menu_get_object()) { | |
| 1775 $variables['node'] = $node; | |
| 1776 } | |
| 1777 | |
| 1778 // Compile a list of classes that are going to be applied to the body element. | |
| 1779 // This allows advanced theming based on context (home page, node of certain type, etc.). | |
| 1780 $body_classes = array(); | |
| 1781 // Add a class that tells us whether we're on the front page or not. | |
| 1782 $body_classes[] = $variables['is_front'] ? 'front' : 'not-front'; | |
| 1783 // Add a class that tells us whether the page is viewed by an authenticated user or not. | |
| 1784 $body_classes[] = $variables['logged_in'] ? 'logged-in' : 'not-logged-in'; | |
| 1785 // Add arg(0) to make it possible to theme the page depending on the current page | |
| 1786 // type (e.g. node, admin, user, etc.). To avoid illegal characters in the class, | |
| 1787 // we're removing everything disallowed. We are not using 'a-z' as that might leave | |
| 1788 // in certain international characters (e.g. German umlauts). | |
| 1789 $body_classes[] = preg_replace('![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s', '', 'page-'. form_clean_id(drupal_strtolower(arg(0)))); | |
| 1790 // If on an individual node page, add the node type. | |
| 1791 if (isset($variables['node']) && $variables['node']->type) { | |
| 1792 $body_classes[] = 'node-type-'. form_clean_id($variables['node']->type); | |
| 1793 } | |
| 1794 // Add information about the number of sidebars. | |
| 1795 if ($variables['layout'] == 'both') { | |
| 1796 $body_classes[] = 'two-sidebars'; | |
| 1797 } | |
| 1798 elseif ($variables['layout'] == 'none') { | |
| 1799 $body_classes[] = 'no-sidebars'; | |
| 1800 } | |
| 1801 else { | |
| 1802 $body_classes[] = 'one-sidebar sidebar-'. $variables['layout']; | |
| 1803 } | |
| 1804 // Implode with spaces. | |
| 1805 $variables['body_classes'] = implode(' ', $body_classes); | |
| 1806 | |
| 1807 // Build a list of suggested template files in order of specificity. One | |
| 1808 // suggestion is made for every element of the current path, though | |
| 1809 // numeric elements are not carried to subsequent suggestions. For example, | |
| 1810 // http://www.example.com/node/1/edit would result in the following | |
| 1811 // suggestions: | |
| 1812 // | |
| 1813 // page-node-edit.tpl.php | |
| 1814 // page-node-1.tpl.php | |
| 1815 // page-node.tpl.php | |
| 1816 // page.tpl.php | |
| 1817 $i = 0; | |
| 1818 $suggestion = 'page'; | |
| 1819 $suggestions = array(); | |
| 1820 while ($arg = arg($i++)) { | |
| 1821 $suggestions[] = $suggestion .'-'. $arg; | |
| 1822 if (!is_numeric($arg)) { | |
| 1823 $suggestion .= '-'. $arg; | |
| 1824 } | |
| 1825 } | |
| 1826 if (drupal_is_front_page()) { | |
| 1827 $suggestions[] = 'page-front'; | |
| 1828 } | |
| 1829 | |
| 1830 if ($suggestions) { | |
| 1831 $variables['template_files'] = $suggestions; | |
| 1832 } | |
| 1833 } | |
| 1834 | |
| 1835 /** | |
| 1836 * Process variables for node.tpl.php | |
| 1837 * | |
| 1838 * Most themes utilize their own copy of node.tpl.php. The default is located | |
| 1839 * inside "modules/node/node.tpl.php". Look in there for the full list of | |
| 1840 * variables. | |
| 1841 * | |
| 1842 * The $variables array contains the following arguments: | |
| 1843 * - $node | |
| 1844 * - $teaser | |
| 1845 * - $page | |
| 1846 * | |
| 1847 * @see node.tpl.php | |
| 1848 */ | |
| 1849 function template_preprocess_node(&$variables) { | |
| 1850 $node = $variables['node']; | |
| 1851 if (module_exists('taxonomy')) { | |
| 1852 $variables['taxonomy'] = taxonomy_link('taxonomy terms', $node); | |
| 1853 } | |
| 1854 else { | |
| 1855 $variables['taxonomy'] = array(); | |
| 1856 } | |
| 1857 | |
| 1858 if ($variables['teaser'] && $node->teaser) { | |
| 1859 $variables['content'] = $node->teaser; | |
| 1860 } | |
| 1861 elseif (isset($node->body)) { | |
| 1862 $variables['content'] = $node->body; | |
| 1863 } | |
| 1864 else { | |
| 1865 $variables['content'] = ''; | |
| 1866 } | |
| 1867 | |
| 1868 $variables['date'] = format_date($node->created); | |
| 1869 $variables['links'] = !empty($node->links) ? theme('links', $node->links, array('class' => 'links inline')) : ''; | |
| 1870 $variables['name'] = theme('username', $node); | |
| 1871 $variables['node_url'] = url('node/'. $node->nid); | |
| 1872 $variables['terms'] = theme('links', $variables['taxonomy'], array('class' => 'links inline')); | |
| 1873 $variables['title'] = check_plain($node->title); | |
| 1874 | |
| 1875 // Flatten the node object's member fields. | |
| 1876 $variables = array_merge((array)$node, $variables); | |
| 1877 | |
| 1878 // Display info only on certain node types. | |
| 1879 if (theme_get_setting('toggle_node_info_'. $node->type)) { | |
| 1880 $variables['submitted'] = theme('node_submitted', $node); | |
| 1881 $variables['picture'] = theme_get_setting('toggle_node_user_picture') ? theme('user_picture', $node) : ''; | |
| 1882 } | |
| 1883 else { | |
| 1884 $variables['submitted'] = ''; | |
| 1885 $variables['picture'] = ''; | |
| 1886 } | |
| 1887 // Clean up name so there are no underscores. | |
| 1888 $variables['template_files'][] = 'node-'. $node->type; | |
| 1889 } | |
| 1890 | |
| 1891 /** | |
| 1892 * Process variables for block.tpl.php | |
| 1893 * | |
| 1894 * Prepare the values passed to the theme_block function to be passed | |
| 1895 * into a pluggable template engine. Uses block properties to generate a | |
| 1896 * series of template file suggestions. If none are found, the default | |
| 1897 * block.tpl.php is used. | |
| 1898 * | |
| 1899 * Most themes utilize their own copy of block.tpl.php. The default is located | |
| 1900 * inside "modules/system/block.tpl.php". Look in there for the full list of | |
| 1901 * variables. | |
| 1902 * | |
| 1903 * The $variables array contains the following arguments: | |
| 1904 * - $block | |
| 1905 * | |
| 1906 * @see block.tpl.php | |
| 1907 */ | |
| 1908 function template_preprocess_block(&$variables) { | |
| 1909 static $block_counter = array(); | |
| 1910 // All blocks get an independent counter for each region. | |
| 1911 if (!isset($block_counter[$variables['block']->region])) { | |
| 1912 $block_counter[$variables['block']->region] = 1; | |
| 1913 } | |
| 1914 // Same with zebra striping. | |
| 1915 $variables['block_zebra'] = ($block_counter[$variables['block']->region] % 2) ? 'odd' : 'even'; | |
| 1916 $variables['block_id'] = $block_counter[$variables['block']->region]++; | |
| 1917 | |
| 1918 $variables['template_files'][] = 'block-'. $variables['block']->region; | |
| 1919 $variables['template_files'][] = 'block-'. $variables['block']->module; | |
| 1920 $variables['template_files'][] = 'block-'. $variables['block']->module .'-'. $variables['block']->delta; | |
| 1921 } | |
| 1922 |
