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 |