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