root / drupal7 / sites / all / modules / panels / plugins / display_renderers / panels_renderer_standard.class.php @ 64156087
1 |
<?php
|
---|---|
2 |
|
3 |
/**
|
4 |
* @file
|
5 |
*/
|
6 |
|
7 |
/**
|
8 |
* The standard render pipeline for a Panels display object.
|
9 |
*
|
10 |
* Given a fully-loaded panels_display object, this class will turn its
|
11 |
* combination of layout, panes, and styles into HTML, invoking caching
|
12 |
* appropriately along the way. Interacting with the renderer externally is
|
13 |
* very simple - just pass it the display object and call the render() method:
|
14 |
*
|
15 |
* @code
|
16 |
* // given that $display is a fully loaded Panels display object
|
17 |
* $renderer = panels_get_renderer_handler('standard', $display)
|
18 |
* $html_output = $renderer->render();
|
19 |
* @endcode
|
20 |
*
|
21 |
* Internally, the render pipeline is divided into two phases, prepare and
|
22 |
* render:
|
23 |
* - The prepare phase transforms the skeletal data on the provided
|
24 |
* display object into a structure that is expected by the render phase.
|
25 |
* It is divided into a series of discrete sub-methods and operates
|
26 |
* primarily by passing parameters, all with the intention of making
|
27 |
* subclassing easier.
|
28 |
* - The render phase relies primarily on data stored in the renderer object's
|
29 |
* properties, presumably set in the prepare phase. It iterates through the
|
30 |
* rendering of each pane, pane styling, placement in panel regions, region
|
31 |
* styling, and finally the arrangement of rendered regions in the layout.
|
32 |
* Caching, if in use, is triggered per pane, or on the entire display.
|
33 |
*
|
34 |
* In short: prepare builds conf, render renders conf. Subclasses should respect
|
35 |
* this separation of responsibilities by adhering to these loose guidelines,
|
36 |
* given a loaded display object:
|
37 |
* - If your renderer needs to modify the datastructure representing what is
|
38 |
* to be rendered (panes and their conf, styles, caching, etc.), it should
|
39 |
* use the prepare phase.
|
40 |
* - If your renderer needs to modify the manner in which that renderable
|
41 |
* datastructure data is rendered, it should use the render phase.
|
42 |
*
|
43 |
* In the vast majority of use cases, this standard renderer will be sufficient
|
44 |
* and need not be switched out/subclassed; style and/or layout plugins can
|
45 |
* accommodate nearly every use case. If you think you might need a custom
|
46 |
* renderer, consider the following criteria/examples:
|
47 |
* - Some additional markup needs to be added to EVERY SINGLE panel.
|
48 |
* - Given a full display object, just render one pane.
|
49 |
* - Show a Panels admin interface.
|
50 |
*
|
51 |
* The system is almost functionally identical to the old procedural approach,
|
52 |
* with some exceptions (@see panels_renderer_legacy for details). The approach
|
53 |
* here differs primarily in its friendliness to tweaking in subclasses.
|
54 |
*/
|
55 |
/**
|
56 |
*
|
57 |
*/
|
58 |
class panels_renderer_standard { |
59 |
/**
|
60 |
* The fully-loaded Panels display object that is to be rendered. "Fully
|
61 |
* loaded" is defined as:
|
62 |
* 1. Having been produced by panels_load_displays(), whether or this page
|
63 |
* request or at some time in the past and the object was exported.
|
64 |
* 2. Having had some external code attach context data ($display->context),
|
65 |
* in the exact form expected by panes. Context matching is delicate,
|
66 |
* typically relying on exact string matches, so special attention must
|
67 |
* be taken.
|
68 |
*
|
69 |
* @var panels_display
|
70 |
*/
|
71 |
var $display; |
72 |
|
73 |
/**
|
74 |
* An associative array of loaded plugins. Used primarily as a central
|
75 |
* location for storing plugins that require additional loading beyond
|
76 |
* reading the plugin definition, which is already statically cached by
|
77 |
* ctools_get_plugins(). An example is layout plugins, which can optionally
|
78 |
* have a callback that determines the set of panel regions available at
|
79 |
* runtime.
|
80 |
*
|
81 |
* @var array
|
82 |
*/
|
83 |
var $plugins = array(); |
84 |
|
85 |
/**
|
86 |
* A multilevel array of rendered data. The first level of the array
|
87 |
* indicates the type of rendered data, typically with up to three keys:
|
88 |
* 'layout', 'regions', and 'panes'. The relevant rendered data is stored as
|
89 |
* the value for each of these keys as it is generated:
|
90 |
* - 'panes' are an associative array of rendered output, keyed on pane id.
|
91 |
* - 'regions' are an associative array of rendered output, keyed on region
|
92 |
* name.
|
93 |
* - 'layout' is the whole of the rendered output.
|
94 |
*
|
95 |
* @var array
|
96 |
*/
|
97 |
var $rendered = array(); |
98 |
|
99 |
/**
|
100 |
* A multilevel array of data prepared for rendering. The first level of the
|
101 |
* array indicates the type of prepared data. The standard renderer populates
|
102 |
* and uses two top-level keys, 'panes' and 'regions':
|
103 |
* - 'panes' are an associative array of pane objects to be rendered, keyed
|
104 |
* on pane id and sorted into proper rendering order.
|
105 |
* - 'regions' are an associative array of regions, keyed on region name,
|
106 |
* each of which is itself an indexed array of pane ids in the order in
|
107 |
* which those panes appear in that region.
|
108 |
*
|
109 |
* @var array
|
110 |
*/
|
111 |
var $prepared = array(); |
112 |
|
113 |
/**
|
114 |
* Boolean state variable, indicating whether or not the prepare() method has
|
115 |
* been run.
|
116 |
*
|
117 |
* This state is checked in panels_renderer_standard::render_layout() to
|
118 |
* determine whether the prepare method should be automatically triggered.
|
119 |
*
|
120 |
* @var bool
|
121 |
*/
|
122 |
var $prep_run = FALSE; |
123 |
|
124 |
/**
|
125 |
* The plugin that defines this handler.
|
126 |
*/
|
127 |
var $plugin = FALSE; |
128 |
|
129 |
/**
|
130 |
* TRUE if this renderer is rendering in administrative mode
|
131 |
* which will allow layouts to have extra functionality.
|
132 |
*
|
133 |
* @var bool
|
134 |
*/
|
135 |
var $admin = FALSE; |
136 |
|
137 |
/**
|
138 |
* Where to add standard meta information. There are three possibilities:
|
139 |
* - standard: Put the meta information in the normal location. Default.
|
140 |
* - inline: Put the meta information directly inline. This will
|
141 |
* not work for javascript.
|
142 |
*
|
143 |
* @var string
|
144 |
*/
|
145 |
var $meta_location = 'standard'; |
146 |
|
147 |
/**
|
148 |
* Include rendered HTML prior to the layout.
|
149 |
*
|
150 |
* @var string
|
151 |
*/
|
152 |
var $prefix = ''; |
153 |
|
154 |
/**
|
155 |
* Include rendered HTML after the layout.
|
156 |
*
|
157 |
* @var string
|
158 |
*/
|
159 |
var $suffix = ''; |
160 |
|
161 |
/**
|
162 |
* Boolean flag indicating whether to render the layout even if all rendered
|
163 |
* regions are blank. If FALSE, the layout renders as an empty string (without
|
164 |
* prefix or suffix) if not in administrative mode.
|
165 |
*
|
166 |
* @var bool
|
167 |
*/
|
168 |
var $show_empty_layout = TRUE; |
169 |
|
170 |
/**
|
171 |
* Receive and store the display object to be rendered.
|
172 |
*
|
173 |
* This is a psuedo-constructor that should typically be called immediately
|
174 |
* after object construction.
|
175 |
*
|
176 |
* @param array $plugin
|
177 |
* The definition of the renderer plugin.
|
178 |
* @param panels_display $display
|
179 |
* The panels display object to be rendered.
|
180 |
*/
|
181 |
function init($plugin, &$display) { |
182 |
$this->plugin = $plugin; |
183 |
$layout = panels_get_layout($display->layout); |
184 |
$this->display = &$display; |
185 |
$this->plugins['layout'] = $layout; |
186 |
if (!isset($layout['regions'])) { |
187 |
$this->plugins['layout']['regions'] = panels_get_regions($layout, $display); |
188 |
} |
189 |
|
190 |
if (empty($this->plugins['layout'])) { |
191 |
watchdog('panels', "Layout: @layout couldn't been found, maybe the theme is disabled.", array('@layout' => $display->layout)); |
192 |
} |
193 |
} |
194 |
|
195 |
/**
|
196 |
* Get the Panels storage oparation for a given renderer AJAX method.
|
197 |
*
|
198 |
* @param string $method
|
199 |
* The method name.
|
200 |
*
|
201 |
* @return string
|
202 |
* The Panels storage op.
|
203 |
*/
|
204 |
function get_panels_storage_op_for_ajax($method) { |
205 |
return 'read'; |
206 |
} |
207 |
|
208 |
/**
|
209 |
* Prepare the attached display for rendering.
|
210 |
*
|
211 |
* This is the outermost prepare method. It calls several sub-methods as part
|
212 |
* of the overall preparation process. This compartmentalization is intended
|
213 |
* to ease the task of modifying renderer behavior in child classes.
|
214 |
*
|
215 |
* If you override this method, it is important that you either call this
|
216 |
* method via parent::prepare(), or manually set $this->prep_run = TRUE.
|
217 |
*
|
218 |
* @param mixed $external_settings
|
219 |
* An optional parameter allowing external code to pass in additional
|
220 |
* settings for use in the preparation process. Not used in the default
|
221 |
* renderer, but included for interface consistency.
|
222 |
*/
|
223 |
function prepare($external_settings = NULL) { |
224 |
$this->prepare_panes($this->display->content); |
225 |
$this->prepare_regions($this->display->panels, $this->display->panel_settings); |
226 |
$this->prep_run = TRUE; |
227 |
} |
228 |
|
229 |
/**
|
230 |
* Prepare the list of panes to be rendered, accounting for visibility/access
|
231 |
* settings and rendering order.
|
232 |
*
|
233 |
* This method represents the standard approach for determining the list of
|
234 |
* panes to be rendered that is compatible with all parts of the Panels
|
235 |
* architecture. It first applies visibility & access checks, then sorts panes
|
236 |
* into their proper rendering order, and returns the result as an array.
|
237 |
*
|
238 |
* Inheriting classes should override this method if that renderer needs to
|
239 |
* regularly make additions to the set of panes that will be rendered.
|
240 |
*
|
241 |
* @param array $panes
|
242 |
* An associative array of pane data (stdClass objects), keyed on pane id.
|
243 |
*
|
244 |
* @return array
|
245 |
* An associative array of panes to be rendered, keyed on pane id and sorted
|
246 |
* into proper rendering order.
|
247 |
*/
|
248 |
function prepare_panes($panes) { |
249 |
ctools_include('content');
|
250 |
// Use local variables as writing to them is very slightly faster.
|
251 |
$first = $normal = $last = array(); |
252 |
|
253 |
// Prepare the list of panes to be rendered.
|
254 |
foreach ($panes as $pid => $pane) { |
255 |
if (empty($this->admin)) { |
256 |
// TODO remove in 7.x and ensure the upgrade path weeds out any stragglers; it's been long enough.
|
257 |
$pane->shown = !empty($pane->shown); |
258 |
// Guarantee this field exists.
|
259 |
// If this pane is not visible to the user, skip out and do the next one.
|
260 |
if (!$pane->shown || !panels_pane_access($pane, $this->display)) { |
261 |
continue;
|
262 |
} |
263 |
} |
264 |
|
265 |
// If the pane's subtype is unique, get it so that
|
266 |
// hook_ctools_content_subtype_alter() and/or
|
267 |
// hook_ctools_block_info() will be called.
|
268 |
if ($pane->type != $pane->subtype) { |
269 |
$content_type = ctools_content_get_subtype($pane->type, $pane->subtype); |
270 |
} |
271 |
else {
|
272 |
$content_type = ctools_get_content_type($pane->type); |
273 |
} |
274 |
|
275 |
// If this pane wants to render last, add it to the $last array. We allow
|
276 |
// this because some panes need to be rendered after other panes,
|
277 |
// primarily so they can do things like the leftovers of forms.
|
278 |
if (!empty($content_type['render last'])) { |
279 |
$last[$pid] = $pane; |
280 |
} |
281 |
// If it wants to render first, add it to the $first array. This is used
|
282 |
// by panes that need to do some processing before other panes are
|
283 |
// rendered.
|
284 |
elseif (!empty($content_type['render first'])) { |
285 |
$first[$pid] = $pane; |
286 |
} |
287 |
// Otherwise, render it in the normal order.
|
288 |
else {
|
289 |
$normal[$pid] = $pane; |
290 |
} |
291 |
} |
292 |
$this->prepared['panes'] = $first + $normal + $last; |
293 |
|
294 |
// Allow other modules the alter the prepared panes array.
|
295 |
drupal_alter('panels_panes_prepared', $this->prepared['panes'], $this); |
296 |
|
297 |
return $this->prepared['panes']; |
298 |
} |
299 |
|
300 |
/**
|
301 |
* Prepare the list of regions to be rendered.
|
302 |
*
|
303 |
* This method is primarily about properly initializing the style plugin that
|
304 |
* will be used to render the region. This is crucial as regions cannot be
|
305 |
* rendered without a style plugin (in keeping with Panels' philosophy of
|
306 |
* hardcoding none of its output), but for most regions no style has been
|
307 |
* explicitly set. The logic here is what accommodates that situation:
|
308 |
* - If a region has had its style explicitly set, then we fetch that plugin
|
309 |
* and continue.
|
310 |
* - If the region has no explicit style, but a style was set at the display
|
311 |
* level, then inherit the style from the display.
|
312 |
* - If neither the region nor the dispay have explicitly set styles, then
|
313 |
* fall back to the hardcoded 'default' style, a very minimal style.
|
314 |
*
|
315 |
* The other important task accomplished by this method is ensuring that even
|
316 |
* regions without any panes are still properly prepared for the rendering
|
317 |
* process. This is essential because the way Panels loads display objects
|
318 |
* (@see panels_load_displays) results only in a list of regions that
|
319 |
* contain panes - not necessarily all the regions defined by the layout
|
320 |
* plugin, which can only be determined by asking the plugin at runtime. This
|
321 |
* method consults that retrieved list of regions and prepares all of those,
|
322 |
* ensuring none are inadvertently skipped.
|
323 |
*
|
324 |
* @param array $region_pane_list
|
325 |
* An associative array of pane ids, keyed on the region to which those pids
|
326 |
* are assigned. In the default case, this is $display->panels.
|
327 |
* @param array $settings
|
328 |
* All known region style settings, including both the top-level display's
|
329 |
* settings (if any) and all region-specific settings (if any).
|
330 |
*
|
331 |
* @return array
|
332 |
* An array of regions prepared for rendering.
|
333 |
*/
|
334 |
function prepare_regions($region_pane_list, $settings) { |
335 |
// Initialize defaults to be used for regions without their own explicit
|
336 |
// settings. Use display settings if they exist, else hardcoded defaults.
|
337 |
$default = array( |
338 |
'style' => panels_get_style(!empty($settings['style']) ? $settings['style'] : 'default'), |
339 |
'style settings' => isset($settings['style_settings']['default']) ? $settings['style_settings']['default'] : array(), |
340 |
); |
341 |
|
342 |
$regions = array(); |
343 |
if (empty($settings)) { |
344 |
// No display/panel region settings exist, init all with the defaults.
|
345 |
foreach ($this->plugins['layout']['regions'] as $region_id => $title) { |
346 |
// Ensure this region has at least an empty panes array.
|
347 |
$panes = !empty($region_pane_list[$region_id]) ? $region_pane_list[$region_id] : array(); |
348 |
|
349 |
$regions[$region_id] = $default; |
350 |
$regions[$region_id]['pids'] = $panes; |
351 |
} |
352 |
} |
353 |
else {
|
354 |
// Some settings exist; iterate through each region and set individually.
|
355 |
foreach ($this->plugins['layout']['regions'] as $region_id => $title) { |
356 |
// Ensure this region has at least an empty panes array.
|
357 |
$panes = !empty($region_pane_list[$region_id]) ? $region_pane_list[$region_id] : array(); |
358 |
if (empty($settings[$region_id]['style']) || $settings[$region_id]['style'] == -1) { |
359 |
$regions[$region_id] = $default; |
360 |
} |
361 |
else {
|
362 |
$regions[$region_id]['style'] = panels_get_style($settings[$region_id]['style']); |
363 |
$regions[$region_id]['style settings'] = isset($settings['style_settings'][$region_id]) ? $settings['style_settings'][$region_id] : array(); |
364 |
} |
365 |
$regions[$region_id]['pids'] = $panes; |
366 |
} |
367 |
} |
368 |
|
369 |
$this->prepared['regions'] = $regions; |
370 |
return $this->prepared['regions']; |
371 |
} |
372 |
|
373 |
/**
|
374 |
* Build inner content, then hand off to layout-specified theme function for
|
375 |
* final render step.
|
376 |
*
|
377 |
* This is the outermost method in the Panels render pipeline. It calls the
|
378 |
* inner methods, which return a content array, which is in turn passed to the
|
379 |
* theme function specified in the layout plugin.
|
380 |
*
|
381 |
* @return string
|
382 |
* Themed & rendered HTML output.
|
383 |
*/
|
384 |
function render() { |
385 |
// Let the display refer back to the renderer.
|
386 |
$this->display->renderer_handler = $this; |
387 |
|
388 |
// Attach out-of-band data first.
|
389 |
$this->add_meta();
|
390 |
|
391 |
if (empty($this->display->cache['method']) || !empty($this->display->skip_cache)) { |
392 |
return $this->render_layout(); |
393 |
} |
394 |
else {
|
395 |
$cache = panels_get_cached_content($this->display, $this->display->args, $this->display->context); |
396 |
if ($cache === FALSE) { |
397 |
$cache = new panels_cache_object(); |
398 |
$cache->set_content($this->render_layout()); |
399 |
panels_set_cached_content($cache, $this->display, $this->display->args, $this->display->context); |
400 |
} |
401 |
return $cache->content; |
402 |
} |
403 |
} |
404 |
|
405 |
/**
|
406 |
* Perform display/layout-level render operations.
|
407 |
*
|
408 |
* This method triggers all the inner pane/region rendering processes, passes
|
409 |
* that to the layout plugin's theme callback, and returns the rendered HTML.
|
410 |
*
|
411 |
* If display-level caching is enabled and that cache is warm, this method
|
412 |
* will not be called.
|
413 |
*
|
414 |
* @return string
|
415 |
* The HTML string representing the entire rendered, themed panel.
|
416 |
*/
|
417 |
function render_layout() { |
418 |
if (empty($this->prep_run)) { |
419 |
$this->prepare();
|
420 |
} |
421 |
$this->render_panes();
|
422 |
$this->render_regions();
|
423 |
|
424 |
if ($this->admin && !empty($this->plugins['layout']['admin theme'])) { |
425 |
$theme = $this->plugins['layout']['admin theme']; |
426 |
} |
427 |
else {
|
428 |
$theme = $this->plugins['layout']['theme']; |
429 |
} |
430 |
|
431 |
// Determine whether to render layout.
|
432 |
$show = TRUE; |
433 |
if (!$this->show_empty_layout && !$this->admin) { |
434 |
$show = FALSE; |
435 |
// Render layout if any region is not empty.
|
436 |
foreach ($this->rendered['regions'] as $region) { |
437 |
if (is_string($region) && $region !== '') { |
438 |
$show = TRUE; |
439 |
break;
|
440 |
} |
441 |
} |
442 |
} |
443 |
if (!$show) { |
444 |
return;
|
445 |
} |
446 |
|
447 |
$this->rendered['layout'] = theme($theme, array('css_id' => check_plain($this->display->css_id), 'content' => $this->rendered['regions'], 'settings' => $this->display->layout_settings, 'display' => $this->display, 'layout' => $this->plugins['layout'], 'renderer' => $this)); |
448 |
return $this->prefix . $this->rendered['layout'] . $this->suffix; |
449 |
} |
450 |
|
451 |
/**
|
452 |
* Attach out-of-band page metadata (e.g., CSS and JS).
|
453 |
*
|
454 |
* This must be done before render, because panels-within-panels must have
|
455 |
* their CSS added in the right order: inner content before outer content.
|
456 |
*/
|
457 |
function add_meta() { |
458 |
global $theme; |
459 |
|
460 |
if (!empty($this->plugins['layout']['css'])) { |
461 |
// Do not use the path_to_theme() function, because it returns the
|
462 |
// $GLOBALS['theme_path'] value, which may be overriden in the theme()
|
463 |
// function when the theme hook defines the key 'theme path'.
|
464 |
$theme_path = isset($theme) ? drupal_get_path('theme', $theme) : ''; |
465 |
|
466 |
$css = $this->plugins['layout']['css']; |
467 |
if (!is_array($css)) { |
468 |
$css = array($css); |
469 |
} |
470 |
|
471 |
// Load each of the CSS files defined in this layout.
|
472 |
foreach ($css as $file) { |
473 |
if (!empty($theme_path) && file_exists($theme_path . '/' . $file)) { |
474 |
$this->add_css($theme_path . '/' . $file); |
475 |
} |
476 |
else {
|
477 |
$this->add_css($this->plugins['layout']['path'] . '/' . $file); |
478 |
} |
479 |
} |
480 |
} |
481 |
|
482 |
if ($this->admin && isset($this->plugins['layout']['admin css'])) { |
483 |
$admin_css = $this->plugins['layout']['admin css']; |
484 |
if (!is_array($admin_css)) { |
485 |
$admin_css = array($admin_css); |
486 |
} |
487 |
foreach ($admin_css as $file) { |
488 |
$this->add_css($this->plugins['layout']['path'] . '/' . $file); |
489 |
} |
490 |
} |
491 |
} |
492 |
|
493 |
/**
|
494 |
* Add CSS information to the renderer.
|
495 |
*
|
496 |
* To facilitate previews over Views, CSS can now be added in a manner
|
497 |
* that does not necessarily mean just using drupal_add_css. Therefore,
|
498 |
* during the panel rendering process, this method can be used to add
|
499 |
* css and make certain that ti gets to the proper location.
|
500 |
*
|
501 |
* The arguments should exactly match drupal_add_css().
|
502 |
*
|
503 |
* @see drupal_add_css
|
504 |
*/
|
505 |
function add_css($filename) { |
506 |
switch ($this->meta_location) { |
507 |
case 'standard': |
508 |
drupal_add_css($filename);
|
509 |
break;
|
510 |
|
511 |
case 'inline': |
512 |
$url = base_path() . $filename; |
513 |
$this->prefix .= '<link type="text/css" rel="stylesheet" href="' . file_create_url($url) . '" />' . "\n"; |
514 |
break;
|
515 |
} |
516 |
} |
517 |
|
518 |
/**
|
519 |
* Render all prepared panes, first by dispatching to their plugin's render
|
520 |
* callback, then handing that output off to the pane's style plugin.
|
521 |
*
|
522 |
* @return array
|
523 |
* The array of rendered panes, keyed on pane pid.
|
524 |
*/
|
525 |
function render_panes() { |
526 |
drupal_alter('panels_prerender_panes', $this); |
527 |
ctools_include('content');
|
528 |
|
529 |
// First, render all the panes into little boxes.
|
530 |
$this->rendered['panes'] = array(); |
531 |
foreach ($this->prepared['panes'] as $pid => $pane) { |
532 |
$content = $this->render_pane($pane); |
533 |
if ($content) { |
534 |
$this->rendered['panes'][$pid] = $content; |
535 |
} |
536 |
} |
537 |
return $this->rendered['panes']; |
538 |
} |
539 |
|
540 |
/**
|
541 |
* Render a pane using its designated style.
|
542 |
*
|
543 |
* This method also manages 'title pane' functionality, where the title from
|
544 |
* an individual pane can be bubbled up to take over the title for the entire
|
545 |
* display.
|
546 |
*
|
547 |
* @param object $pane
|
548 |
* A Panels pane object, as loaded from the database.
|
549 |
*/
|
550 |
function render_pane(&$pane) { |
551 |
module_invoke_all('panels_pane_prerender', $pane); |
552 |
|
553 |
$content = $this->render_pane_content($pane); |
554 |
if ($this->display->hide_title == PANELS_TITLE_PANE && !empty($this->display->title_pane) && $this->display->title_pane == $pane->pid) { |
555 |
|
556 |
// If the user selected to override the title with nothing, and selected
|
557 |
// this as the title pane, assume the user actually wanted the original
|
558 |
// title to bubble up to the top but not actually be used on the pane.
|
559 |
if (empty($content->title) && !empty($content->original_title)) { |
560 |
$this->display->stored_pane_title = $content->original_title; |
561 |
} |
562 |
else {
|
563 |
$this->display->stored_pane_title = !empty($content->title) ? $content->title : ''; |
564 |
} |
565 |
} |
566 |
|
567 |
if (!empty($content->content)) { |
568 |
if (!empty($pane->style['style'])) { |
569 |
$style = panels_get_style($pane->style['style']); |
570 |
|
571 |
if (isset($style) && isset($style['render pane'])) { |
572 |
$output = theme($style['render pane'], array('content' => $content, 'pane' => $pane, 'display' => $this->display, 'style' => $style, 'settings' => $pane->style['settings'])); |
573 |
|
574 |
// This could be null if no theme function existed.
|
575 |
if (isset($output)) { |
576 |
return $output; |
577 |
} |
578 |
} |
579 |
} |
580 |
|
581 |
// Fallback.
|
582 |
return theme('panels_pane', array('content' => $content, 'pane' => $pane, 'display' => $this->display)); |
583 |
} |
584 |
} |
585 |
|
586 |
/**
|
587 |
* Render the interior contents of a single pane.
|
588 |
*
|
589 |
* This method retrieves pane content and produces a ready-to-render content
|
590 |
* object. It also manages pane-specific caching.
|
591 |
*
|
592 |
* @param object $pane
|
593 |
* A Panels pane object, as loaded from the database.
|
594 |
*
|
595 |
* @return stdClass $content
|
596 |
* A renderable object, containing a subject, content, etc. Based on the
|
597 |
* renderable objects used by the block system.
|
598 |
*/
|
599 |
function render_pane_content(&$pane) { |
600 |
ctools_include('context');
|
601 |
// TODO finally safe to remove this check?
|
602 |
if (!is_array($this->display->context)) { |
603 |
watchdog('panels', 'renderer::render_pane_content() hit with a non-array for the context', $this->display, WATCHDOG_DEBUG); |
604 |
$this->display->context = array(); |
605 |
} |
606 |
|
607 |
$caching = !empty($pane->cache['method']) && empty($this->display->skip_cache); |
608 |
if ($caching && ($cache = panels_get_cached_content($this->display, $this->display->args, $this->display->context, $pane))) { |
609 |
$content = $cache->content; |
610 |
} |
611 |
else {
|
612 |
if ($caching) { |
613 |
// This is created before rendering so that calls to drupal_add_js
|
614 |
// and drupal_add_css will be captured.
|
615 |
$cache = new panels_cache_object(); |
616 |
} |
617 |
|
618 |
$content = ctools_content_render($pane->type, $pane->subtype, $pane->configuration, array(), $this->display->args, $this->display->context); |
619 |
|
620 |
foreach (module_implements('panels_pane_content_alter') as $module) { |
621 |
$function = $module . '_panels_pane_content_alter'; |
622 |
$function($content, $pane, $this->display->args, $this->display->context, $this, $this->display); |
623 |
} |
624 |
if ($caching && isset($cache)) { |
625 |
$cache->set_content($content); |
626 |
panels_set_cached_content($cache, $this->display, $this->display->args, $this->display->context, $pane); |
627 |
$content = $cache->content; |
628 |
} |
629 |
} |
630 |
|
631 |
// If there's content, check if we've css configuration to add.
|
632 |
if (!empty($content)) { |
633 |
// Pass long the css_id that is usually available.
|
634 |
if (!empty($pane->css['css_id'])) { |
635 |
$id = ctools_context_keyword_substitute($pane->css['css_id'], array(), $this->display->context); |
636 |
$content->css_id = check_plain($id); |
637 |
} |
638 |
|
639 |
// Pass long the css_class that is usually available.
|
640 |
if (!empty($pane->css['css_class'])) { |
641 |
$class = ctools_context_keyword_substitute($pane->css['css_class'], array(), $this->display->context, array('css safe' => TRUE)); |
642 |
$content->css_class = check_plain($class); |
643 |
} |
644 |
} |
645 |
|
646 |
return $content; |
647 |
} |
648 |
|
649 |
/**
|
650 |
* Render all prepared regions, placing already-rendered panes into their
|
651 |
* appropriate positions therein.
|
652 |
*
|
653 |
* @return array
|
654 |
* An array of rendered panel regions, keyed on the region name.
|
655 |
*/
|
656 |
function render_regions() { |
657 |
drupal_alter('panels_prerender_regions', $this); |
658 |
$this->rendered['regions'] = array(); |
659 |
|
660 |
// Loop through all panel regions, put all panes that belong to the current
|
661 |
// region in an array, then render the region. Primarily this ensures that
|
662 |
// the panes are arranged in the proper order.
|
663 |
$content = array(); |
664 |
foreach ($this->prepared['regions'] as $region_id => $conf) { |
665 |
$region_panes = array(); |
666 |
foreach ($conf['pids'] as $pid) { |
667 |
// Only include panes for region rendering if they had some output.
|
668 |
if (!empty($this->rendered['panes'][$pid])) { |
669 |
$region_panes[$pid] = $this->rendered['panes'][$pid]; |
670 |
} |
671 |
} |
672 |
$this->rendered['regions'][$region_id] = $this->render_region($region_id, $region_panes); |
673 |
} |
674 |
|
675 |
return $this->rendered['regions']; |
676 |
} |
677 |
|
678 |
/**
|
679 |
* Render a single panel region.
|
680 |
*
|
681 |
* Primarily just a passthrough to the panel region rendering callback
|
682 |
* specified by the style plugin that is attached to the current panel region.
|
683 |
*
|
684 |
* @param $region_id
|
685 |
* The ID of the panel region being rendered
|
686 |
* @param $panes
|
687 |
* An array of panes that are assigned to the panel that's being rendered.
|
688 |
*
|
689 |
* @return string
|
690 |
* The rendered, HTML string output of the passed-in panel region.
|
691 |
*/
|
692 |
function render_region($region_id, $panes) { |
693 |
$style = $this->prepared['regions'][$region_id]['style']; |
694 |
$style_settings = $this->prepared['regions'][$region_id]['style settings']; |
695 |
|
696 |
// Retrieve the pid (can be a panel page id, a mini panel id, etc.), this
|
697 |
// might be used (or even necessary) for some panel display styles.
|
698 |
// TODO: Got to fix this to use panel page name instead of pid, since pid is
|
699 |
// no longer guaranteed. This needs an API to be able to set the final id.
|
700 |
$owner_id = 0; |
701 |
if (isset($this->display->owner) && is_object($this->display->owner) && isset($this->display->owner->id)) { |
702 |
$owner_id = $this->display->owner->id; |
703 |
} |
704 |
|
705 |
$output = theme($style['render region'], array('display' => $this->display, 'owner_id' => $owner_id, 'panes' => $panes, 'settings' => $style_settings, 'region_id' => $region_id, 'style' => $style)); |
706 |
return $output; |
707 |
} |
708 |
|
709 |
} |