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