root / drupal7 / sites / all / modules / panels / plugins / display_renderers / panels_renderer_standard.class.php @ fc2c1c7a
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 |
* Receive and store the display object to be rendered.
|
156 |
*
|
157 |
* This is a psuedo-constructor that should typically be called immediately
|
158 |
* after object construction.
|
159 |
*
|
160 |
* @param array $plugin
|
161 |
* The definition of the renderer plugin.
|
162 |
* @param panels_display $display
|
163 |
* The panels display object to be rendered.
|
164 |
*/
|
165 |
function init($plugin, &$display) { |
166 |
$this->plugin = $plugin; |
167 |
$layout = panels_get_layout($display->layout); |
168 |
$this->display = &$display; |
169 |
$this->plugins['layout'] = $layout; |
170 |
if (!isset($layout['regions'])) { |
171 |
$this->plugins['layout']['regions'] = panels_get_regions($layout, $display); |
172 |
} |
173 |
|
174 |
if (empty($this->plugins['layout'])) { |
175 |
watchdog('panels', "Layout: @layout couldn't been found, maybe the theme is disabled.", array('@layout' => $display->layout)); |
176 |
} |
177 |
} |
178 |
|
179 |
/**
|
180 |
* Prepare the attached display for rendering.
|
181 |
*
|
182 |
* This is the outermost prepare method. It calls several sub-methods as part
|
183 |
* of the overall preparation process. This compartmentalization is intended
|
184 |
* to ease the task of modifying renderer behavior in child classes.
|
185 |
*
|
186 |
* If you override this method, it is important that you either call this
|
187 |
* method via parent::prepare(), or manually set $this->prep_run = TRUE.
|
188 |
*
|
189 |
* @param mixed $external_settings
|
190 |
* An optional parameter allowing external code to pass in additional
|
191 |
* settings for use in the preparation process. Not used in the default
|
192 |
* renderer, but included for interface consistency.
|
193 |
*/
|
194 |
function prepare($external_settings = NULL) { |
195 |
$this->prepare_panes($this->display->content); |
196 |
$this->prepare_regions($this->display->panels, $this->display->panel_settings); |
197 |
$this->prep_run = TRUE; |
198 |
} |
199 |
|
200 |
/**
|
201 |
* Prepare the list of panes to be rendered, accounting for visibility/access
|
202 |
* settings and rendering order.
|
203 |
*
|
204 |
* This method represents the standard approach for determining the list of
|
205 |
* panes to be rendered that is compatible with all parts of the Panels
|
206 |
* architecture. It first applies visibility & access checks, then sorts panes
|
207 |
* into their proper rendering order, and returns the result as an array.
|
208 |
*
|
209 |
* Inheriting classes should override this method if that renderer needs to
|
210 |
* regularly make additions to the set of panes that will be rendered.
|
211 |
*
|
212 |
* @param array $panes
|
213 |
* An associative array of pane data (stdClass objects), keyed on pane id.
|
214 |
* @return array
|
215 |
* An associative array of panes to be rendered, keyed on pane id and sorted
|
216 |
* into proper rendering order.
|
217 |
*/
|
218 |
function prepare_panes($panes) { |
219 |
ctools_include('content');
|
220 |
// Use local variables as writing to them is very slightly faster
|
221 |
$first = $normal = $last = array(); |
222 |
|
223 |
// Prepare the list of panes to be rendered
|
224 |
foreach ($panes as $pid => $pane) { |
225 |
if (empty($this->admin)) { |
226 |
// TODO remove in 7.x and ensure the upgrade path weeds out any stragglers; it's been long enough
|
227 |
$pane->shown = !empty($pane->shown); // guarantee this field exists. |
228 |
// If this pane is not visible to the user, skip out and do the next one
|
229 |
if (!$pane->shown || !panels_pane_access($pane, $this->display)) { |
230 |
continue;
|
231 |
} |
232 |
} |
233 |
|
234 |
// If the pane's subtype is unique, get it so that
|
235 |
// hook_ctools_content_subtype_alter() and/or
|
236 |
// hook_ctools_block_info() will be called.
|
237 |
if ($pane->type != $pane->subtype) { |
238 |
$content_type = ctools_content_get_subtype($pane->type, $pane->subtype); |
239 |
} |
240 |
else {
|
241 |
$content_type = ctools_get_content_type($pane->type); |
242 |
} |
243 |
|
244 |
// If this pane wants to render last, add it to the $last array. We allow
|
245 |
// this because some panes need to be rendered after other panes,
|
246 |
// primarily so they can do things like the leftovers of forms.
|
247 |
if (!empty($content_type['render last'])) { |
248 |
$last[$pid] = $pane; |
249 |
} |
250 |
// If it wants to render first, add it to the $first array. This is used
|
251 |
// by panes that need to do some processing before other panes are
|
252 |
// rendered.
|
253 |
else if (!empty($content_type['render first'])) { |
254 |
$first[$pid] = $pane; |
255 |
} |
256 |
// Otherwise, render it in the normal order.
|
257 |
else {
|
258 |
$normal[$pid] = $pane; |
259 |
} |
260 |
} |
261 |
$this->prepared['panes'] = $first + $normal + $last; |
262 |
|
263 |
// Allow other modules the alter the prepared panes array.
|
264 |
drupal_alter('panels_panes_prepared', $this->prepared['panes'], $this); |
265 |
|
266 |
return $this->prepared['panes']; |
267 |
} |
268 |
|
269 |
/**
|
270 |
* Prepare the list of regions to be rendered.
|
271 |
*
|
272 |
* This method is primarily about properly initializing the style plugin that
|
273 |
* will be used to render the region. This is crucial as regions cannot be
|
274 |
* rendered without a style plugin (in keeping with Panels' philosophy of
|
275 |
* hardcoding none of its output), but for most regions no style has been
|
276 |
* explicitly set. The logic here is what accommodates that situation:
|
277 |
* - If a region has had its style explicitly set, then we fetch that plugin
|
278 |
* and continue.
|
279 |
* - If the region has no explicit style, but a style was set at the display
|
280 |
* level, then inherit the style from the display.
|
281 |
* - If neither the region nor the dispay have explicitly set styles, then
|
282 |
* fall back to the hardcoded 'default' style, a very minimal style.
|
283 |
*
|
284 |
* The other important task accomplished by this method is ensuring that even
|
285 |
* regions without any panes are still properly prepared for the rendering
|
286 |
* process. This is essential because the way Panels loads display objects
|
287 |
* (@see panels_load_displays) results only in a list of regions that
|
288 |
* contain panes - not necessarily all the regions defined by the layout
|
289 |
* plugin, which can only be determined by asking the plugin at runtime. This
|
290 |
* method consults that retrieved list of regions and prepares all of those,
|
291 |
* ensuring none are inadvertently skipped.
|
292 |
*
|
293 |
* @param array $region_pane_list
|
294 |
* An associative array of pane ids, keyed on the region to which those pids
|
295 |
* are assigned. In the default case, this is $display->panels.
|
296 |
* @param array $settings
|
297 |
* All known region style settings, including both the top-level display's
|
298 |
* settings (if any) and all region-specific settings (if any).
|
299 |
* @return array
|
300 |
* An array of regions prepared for rendering.
|
301 |
*/
|
302 |
function prepare_regions($region_pane_list, $settings) { |
303 |
// Initialize defaults to be used for regions without their own explicit
|
304 |
// settings. Use display settings if they exist, else hardcoded defaults.
|
305 |
$default = array( |
306 |
'style' => panels_get_style(!empty($settings['style']) ? $settings['style'] : 'default'), |
307 |
'style settings' => isset($settings['style_settings']['default']) ? $settings['style_settings']['default'] : array(), |
308 |
); |
309 |
|
310 |
$regions = array(); |
311 |
if (empty($settings)) { |
312 |
// No display/panel region settings exist, init all with the defaults.
|
313 |
foreach ($this->plugins['layout']['regions'] as $region_id => $title) { |
314 |
// Ensure this region has at least an empty panes array.
|
315 |
$panes = !empty($region_pane_list[$region_id]) ? $region_pane_list[$region_id] : array(); |
316 |
|
317 |
$regions[$region_id] = $default; |
318 |
$regions[$region_id]['pids'] = $panes; |
319 |
} |
320 |
} |
321 |
else {
|
322 |
// Some settings exist; iterate through each region and set individually.
|
323 |
foreach ($this->plugins['layout']['regions'] as $region_id => $title) { |
324 |
// Ensure this region has at least an empty panes array.
|
325 |
$panes = !empty($region_pane_list[$region_id]) ? $region_pane_list[$region_id] : array(); |
326 |
if (empty($settings[$region_id]['style']) || $settings[$region_id]['style'] == -1) { |
327 |
$regions[$region_id] = $default; |
328 |
} |
329 |
else {
|
330 |
$regions[$region_id]['style'] = panels_get_style($settings[$region_id]['style']); |
331 |
$regions[$region_id]['style settings'] = isset($settings['style_settings'][$region_id]) ? $settings['style_settings'][$region_id] : array(); |
332 |
} |
333 |
$regions[$region_id]['pids'] = $panes; |
334 |
} |
335 |
} |
336 |
|
337 |
$this->prepared['regions'] = $regions; |
338 |
return $this->prepared['regions']; |
339 |
} |
340 |
|
341 |
/**
|
342 |
* Build inner content, then hand off to layout-specified theme function for
|
343 |
* final render step.
|
344 |
*
|
345 |
* This is the outermost method in the Panels render pipeline. It calls the
|
346 |
* inner methods, which return a content array, which is in turn passed to the
|
347 |
* theme function specified in the layout plugin.
|
348 |
*
|
349 |
* @return string
|
350 |
* Themed & rendered HTML output.
|
351 |
*/
|
352 |
function render() { |
353 |
// Let the display refer back to the renderer.
|
354 |
$this->display->renderer_handler = $this; |
355 |
|
356 |
// Attach out-of-band data first.
|
357 |
$this->add_meta();
|
358 |
|
359 |
if (empty($this->display->cache['method']) || !empty($this->display->skip_cache)) { |
360 |
return $this->render_layout(); |
361 |
} |
362 |
else {
|
363 |
$cache = panels_get_cached_content($this->display, $this->display->args, $this->display->context); |
364 |
if ($cache === FALSE) { |
365 |
$cache = new panels_cache_object(); |
366 |
$cache->set_content($this->render_layout()); |
367 |
panels_set_cached_content($cache, $this->display, $this->display->args, $this->display->context); |
368 |
} |
369 |
return $cache->content; |
370 |
} |
371 |
} |
372 |
|
373 |
/**
|
374 |
* Perform display/layout-level render operations.
|
375 |
*
|
376 |
* This method triggers all the inner pane/region rendering processes, passes
|
377 |
* that to the layout plugin's theme callback, and returns the rendered HTML.
|
378 |
*
|
379 |
* If display-level caching is enabled and that cache is warm, this method
|
380 |
* will not be called.
|
381 |
*
|
382 |
* @return string
|
383 |
* The HTML string representing the entire rendered, themed panel.
|
384 |
*/
|
385 |
function render_layout() { |
386 |
if (empty($this->prep_run)) { |
387 |
$this->prepare();
|
388 |
} |
389 |
$this->render_panes();
|
390 |
$this->render_regions();
|
391 |
|
392 |
if ($this->admin && !empty($this->plugins['layout']['admin theme'])) { |
393 |
$theme = $this->plugins['layout']['admin theme']; |
394 |
} |
395 |
else {
|
396 |
$theme = $this->plugins['layout']['theme']; |
397 |
} |
398 |
|
399 |
$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)); |
400 |
return $this->prefix . $this->rendered['layout'] . $this->suffix; |
401 |
} |
402 |
|
403 |
/**
|
404 |
* Attach out-of-band page metadata (e.g., CSS and JS).
|
405 |
*
|
406 |
* This must be done before render, because panels-within-panels must have
|
407 |
* their CSS added in the right order: inner content before outer content.
|
408 |
*/
|
409 |
function add_meta() { |
410 |
global $theme; |
411 |
|
412 |
if (!empty($this->plugins['layout']['css'])) { |
413 |
// Do not use the path_to_theme() function, because it returns the
|
414 |
// $GLOBALS['theme_path'] value, which may be overriden in the theme()
|
415 |
// function when the theme hook defines the key 'theme path'.
|
416 |
$theme_path = isset($theme) ? drupal_get_path('theme', $theme) : ''; |
417 |
|
418 |
$css = $this->plugins['layout']['css']; |
419 |
if (!is_array($css)) { |
420 |
$css = array($css); |
421 |
} |
422 |
|
423 |
// Load each of the CSS files defined in this layout.
|
424 |
foreach ($css as $file) { |
425 |
if (!empty($theme_path) && file_exists($theme_path . '/' . $file)) { |
426 |
$this->add_css($theme_path . '/' . $file); |
427 |
} |
428 |
else {
|
429 |
$this->add_css($this->plugins['layout']['path'] . '/' . $file); |
430 |
} |
431 |
} |
432 |
} |
433 |
|
434 |
if ($this->admin && isset($this->plugins['layout']['admin css'])) { |
435 |
$admin_css = $this->plugins['layout']['admin css']; |
436 |
if (!is_array($admin_css)) { |
437 |
$admin_css = array($admin_css); |
438 |
} |
439 |
foreach ($admin_css as $file) { |
440 |
$this->add_css($this->plugins['layout']['path'] . '/' . $file); |
441 |
} |
442 |
} |
443 |
} |
444 |
|
445 |
/**
|
446 |
* Add CSS information to the renderer.
|
447 |
*
|
448 |
* To facilitate previews over Views, CSS can now be added in a manner
|
449 |
* that does not necessarily mean just using drupal_add_css. Therefore,
|
450 |
* during the panel rendering process, this method can be used to add
|
451 |
* css and make certain that ti gets to the proper location.
|
452 |
*
|
453 |
* The arguments should exactly match drupal_add_css().
|
454 |
*
|
455 |
* @see drupal_add_css
|
456 |
*/
|
457 |
function add_css($filename) { |
458 |
switch ($this->meta_location) { |
459 |
case 'standard': |
460 |
drupal_add_css($filename);
|
461 |
break;
|
462 |
case 'inline': |
463 |
$url = base_path() . $filename; |
464 |
$this->prefix .= '<link type="text/css" rel="stylesheet" href="' . file_create_url($url) . '" />'."\n"; |
465 |
break;
|
466 |
} |
467 |
} |
468 |
|
469 |
/**
|
470 |
* Render all prepared panes, first by dispatching to their plugin's render
|
471 |
* callback, then handing that output off to the pane's style plugin.
|
472 |
*
|
473 |
* @return array
|
474 |
* The array of rendered panes, keyed on pane pid.
|
475 |
*/
|
476 |
function render_panes() { |
477 |
ctools_include('content');
|
478 |
|
479 |
// First, render all the panes into little boxes.
|
480 |
$this->rendered['panes'] = array(); |
481 |
foreach ($this->prepared['panes'] as $pid => $pane) { |
482 |
$content = $this->render_pane($pane); |
483 |
if ($content) { |
484 |
$this->rendered['panes'][$pid] = $content; |
485 |
} |
486 |
} |
487 |
return $this->rendered['panes']; |
488 |
} |
489 |
|
490 |
/**
|
491 |
* Render a pane using its designated style.
|
492 |
*
|
493 |
* This method also manages 'title pane' functionality, where the title from
|
494 |
* an individual pane can be bubbled up to take over the title for the entire
|
495 |
* display.
|
496 |
*
|
497 |
* @param stdClass $pane
|
498 |
* A Panels pane object, as loaded from the database.
|
499 |
*/
|
500 |
function render_pane(&$pane) { |
501 |
module_invoke_all('panels_pane_prerender', $pane); |
502 |
|
503 |
$content = $this->render_pane_content($pane); |
504 |
if ($this->display->hide_title == PANELS_TITLE_PANE && !empty($this->display->title_pane) && $this->display->title_pane == $pane->pid) { |
505 |
|
506 |
// If the user selected to override the title with nothing, and selected
|
507 |
// this as the title pane, assume the user actually wanted the original
|
508 |
// title to bubble up to the top but not actually be used on the pane.
|
509 |
if (empty($content->title) && !empty($content->original_title)) { |
510 |
$this->display->stored_pane_title = $content->original_title; |
511 |
} |
512 |
else {
|
513 |
$this->display->stored_pane_title = !empty($content->title) ? $content->title : ''; |
514 |
} |
515 |
} |
516 |
|
517 |
if (!empty($content->content)) { |
518 |
if (!empty($pane->style['style'])) { |
519 |
$style = panels_get_style($pane->style['style']); |
520 |
|
521 |
if (isset($style) && isset($style['render pane'])) { |
522 |
$output = theme($style['render pane'], array('content' => $content, 'pane' => $pane, 'display' => $this->display, 'style' => $style, 'settings' => $pane->style['settings'])); |
523 |
|
524 |
// This could be null if no theme function existed.
|
525 |
if (isset($output)) { |
526 |
return $output; |
527 |
} |
528 |
} |
529 |
} |
530 |
|
531 |
// fallback
|
532 |
return theme('panels_pane', array('content' => $content, 'pane' => $pane, 'display' => $this->display)); |
533 |
} |
534 |
} |
535 |
|
536 |
/**
|
537 |
* Render the interior contents of a single pane.
|
538 |
*
|
539 |
* This method retrieves pane content and produces a ready-to-render content
|
540 |
* object. It also manages pane-specific caching.
|
541 |
*
|
542 |
* @param stdClass $pane
|
543 |
* A Panels pane object, as loaded from the database.
|
544 |
* @return stdClass $content
|
545 |
* A renderable object, containing a subject, content, etc. Based on the
|
546 |
* renderable objects used by the block system.
|
547 |
*/
|
548 |
function render_pane_content(&$pane) { |
549 |
ctools_include('context');
|
550 |
// TODO finally safe to remove this check?
|
551 |
if (!is_array($this->display->context)) { |
552 |
watchdog('panels', 'renderer::render_pane_content() hit with a non-array for the context', $this->display, WATCHDOG_DEBUG); |
553 |
$this->display->context = array(); |
554 |
} |
555 |
|
556 |
$caching = !empty($pane->cache['method']) && empty($this->display->skip_cache); |
557 |
if ($caching && ($cache = panels_get_cached_content($this->display, $this->display->args, $this->display->context, $pane))) { |
558 |
$content = $cache->content; |
559 |
} |
560 |
else {
|
561 |
if ($caching) { |
562 |
// This is created before rendering so that calls to drupal_add_js
|
563 |
// and drupal_add_css will be captured.
|
564 |
$cache = new panels_cache_object(); |
565 |
} |
566 |
|
567 |
$content = ctools_content_render($pane->type, $pane->subtype, $pane->configuration, array(), $this->display->args, $this->display->context); |
568 |
|
569 |
foreach (module_implements('panels_pane_content_alter') as $module) { |
570 |
$function = $module . '_panels_pane_content_alter'; |
571 |
$function($content, $pane, $this->display->args, $this->display->context, $this, $this->display); |
572 |
} |
573 |
if ($caching && isset($cache)) { |
574 |
$cache->set_content($content); |
575 |
panels_set_cached_content($cache, $this->display, $this->display->args, $this->display->context, $pane); |
576 |
$content = $cache->content; |
577 |
} |
578 |
} |
579 |
|
580 |
// If there's content, check if we've css configuration to add.
|
581 |
if (!empty($content)) { |
582 |
// Pass long the css_id that is usually available.
|
583 |
if (!empty($pane->css['css_id'])) { |
584 |
$content->css_id = check_plain($pane->css['css_id']); |
585 |
} |
586 |
|
587 |
// Pass long the css_class that is usually available.
|
588 |
if (!empty($pane->css['css_class'])) { |
589 |
$content->css_class = check_plain($pane->css['css_class']); |
590 |
} |
591 |
} |
592 |
|
593 |
return $content; |
594 |
} |
595 |
|
596 |
/**
|
597 |
* Render all prepared regions, placing already-rendered panes into their
|
598 |
* appropriate positions therein.
|
599 |
*
|
600 |
* @return array
|
601 |
* An array of rendered panel regions, keyed on the region name.
|
602 |
*/
|
603 |
function render_regions() { |
604 |
$this->rendered['regions'] = array(); |
605 |
|
606 |
// Loop through all panel regions, put all panes that belong to the current
|
607 |
// region in an array, then render the region. Primarily this ensures that
|
608 |
// the panes are arranged in the proper order.
|
609 |
$content = array(); |
610 |
foreach ($this->prepared['regions'] as $region_id => $conf) { |
611 |
$region_panes = array(); |
612 |
foreach ($conf['pids'] as $pid) { |
613 |
// Only include panes for region rendering if they had some output.
|
614 |
if (!empty($this->rendered['panes'][$pid])) { |
615 |
$region_panes[$pid] = $this->rendered['panes'][$pid]; |
616 |
} |
617 |
} |
618 |
$this->rendered['regions'][$region_id] = $this->render_region($region_id, $region_panes); |
619 |
} |
620 |
|
621 |
return $this->rendered['regions']; |
622 |
} |
623 |
|
624 |
/**
|
625 |
* Render a single panel region.
|
626 |
*
|
627 |
* Primarily just a passthrough to the panel region rendering callback
|
628 |
* specified by the style plugin that is attached to the current panel region.
|
629 |
*
|
630 |
* @param $region_id
|
631 |
* The ID of the panel region being rendered
|
632 |
* @param $panes
|
633 |
* An array of panes that are assigned to the panel that's being rendered.
|
634 |
*
|
635 |
* @return string
|
636 |
* The rendered, HTML string output of the passed-in panel region.
|
637 |
*/
|
638 |
function render_region($region_id, $panes) { |
639 |
$style = $this->prepared['regions'][$region_id]['style']; |
640 |
$style_settings = $this->prepared['regions'][$region_id]['style settings']; |
641 |
|
642 |
// Retrieve the pid (can be a panel page id, a mini panel id, etc.), this
|
643 |
// might be used (or even necessary) for some panel display styles.
|
644 |
// TODO: Got to fix this to use panel page name instead of pid, since pid is
|
645 |
// no longer guaranteed. This needs an API to be able to set the final id.
|
646 |
$owner_id = 0; |
647 |
if (isset($this->display->owner) && is_object($this->display->owner) && isset($this->display->owner->id)) { |
648 |
$owner_id = $this->display->owner->id; |
649 |
} |
650 |
|
651 |
$output = theme($style['render region'], array('display' => $this->display, 'owner_id' => $owner_id, 'panes' => $panes, 'settings' => $style_settings, 'region_id' => $region_id, 'style' => $style)); |
652 |
return $output; |
653 |
} |
654 |
} |