|
|
|
@@ -0,0 +1,633 @@
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The standard render pipeline for a Panels display object.
|
|
|
|
|
*
|
|
|
|
|
* Given a fully-loaded panels_display object, this class will turn its
|
|
|
|
|
* combination of layout, panes, and styles into HTML, invoking caching
|
|
|
|
|
* appropriately along the way. Interacting with the renderer externally is
|
|
|
|
|
* very simple - just pass it the display object and call the render() method:
|
|
|
|
|
*
|
|
|
|
|
* @code
|
|
|
|
|
* // given that $display is a fully loaded Panels display object
|
|
|
|
|
* $renderer = panels_get_renderer_handler('standard', $display)
|
|
|
|
|
* $html_output = $renderer->render();
|
|
|
|
|
* @endcode
|
|
|
|
|
*
|
|
|
|
|
* Internally, the render pipeline is divided into two phases, prepare and
|
|
|
|
|
* render:
|
|
|
|
|
* - The prepare phase transforms the skeletal data on the provided
|
|
|
|
|
* display object into a structure that is expected by the render phase.
|
|
|
|
|
* It is divided into a series of discrete sub-methods and operates
|
|
|
|
|
* primarily by passing parameters, all with the intention of making
|
|
|
|
|
* subclassing easier.
|
|
|
|
|
* - The render phase relies primarily on data stored in the renderer object's
|
|
|
|
|
* properties, presumably set in the prepare phase. It iterates through the
|
|
|
|
|
* rendering of each pane, pane styling, placement in panel regions, region
|
|
|
|
|
* styling, and finally the arrangement of rendered regions in the layout.
|
|
|
|
|
* Caching, if in use, is triggered per pane, or on the entire display.
|
|
|
|
|
*
|
|
|
|
|
* In short: prepare builds conf, render renders conf. Subclasses should respect
|
|
|
|
|
* this separation of responsibilities by adhering to these loose guidelines,
|
|
|
|
|
* given a loaded display object:
|
|
|
|
|
* - If your renderer needs to modify the datastructure representing what is
|
|
|
|
|
* to be rendered (panes and their conf, styles, caching, etc.), it should
|
|
|
|
|
* use the prepare phase.
|
|
|
|
|
* - If your renderer needs to modify the manner in which that renderable
|
|
|
|
|
* datastructure data is rendered, it should use the render phase.
|
|
|
|
|
*
|
|
|
|
|
* In the vast majority of use cases, this standard renderer will be sufficient
|
|
|
|
|
* and need not be switched out/subclassed; style and/or layout plugins can
|
|
|
|
|
* accommodate nearly every use case. If you think you might need a custom
|
|
|
|
|
* renderer, consider the following criteria/examples:
|
|
|
|
|
* - Some additional markup needs to be added to EVERY SINGLE panel.
|
|
|
|
|
* - Given a full display object, just render one pane.
|
|
|
|
|
* - Show a Panels admin interface.
|
|
|
|
|
*
|
|
|
|
|
* The system is almost functionally identical to the old procedural approach,
|
|
|
|
|
* with some exceptions (@see panels_renderer_legacy for details). The approach
|
|
|
|
|
* here differs primarily in its friendliness to tweaking in subclasses.
|
|
|
|
|
*/
|
|
|
|
|
class panels_renderer_standard {
|
|
|
|
|
/**
|
|
|
|
|
* The fully-loaded Panels display object that is to be rendered. "Fully
|
|
|
|
|
* loaded" is defined as:
|
|
|
|
|
* 1. Having been produced by panels_load_displays(), whether or this page
|
|
|
|
|
* request or at some time in the past and the object was exported.
|
|
|
|
|
* 2. Having had some external code attach context data ($display->context),
|
|
|
|
|
* in the exact form expected by panes. Context matching is delicate,
|
|
|
|
|
* typically relying on exact string matches, so special attention must
|
|
|
|
|
* be taken.
|
|
|
|
|
*
|
|
|
|
|
* @var panels_display
|
|
|
|
|
*/
|
|
|
|
|
var $display;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* An associative array of loaded plugins. Used primarily as a central
|
|
|
|
|
* location for storing plugins that require additional loading beyond
|
|
|
|
|
* reading the plugin definition, which is already statically cached by
|
|
|
|
|
* ctools_get_plugins(). An example is layout plugins, which can optionally
|
|
|
|
|
* have a callback that determines the set of panel regions available at
|
|
|
|
|
* runtime.
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
|
|
|
|
var $plugins = array();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A multilevel array of rendered data. The first level of the array
|
|
|
|
|
* indicates the type of rendered data, typically with up to three keys:
|
|
|
|
|
* 'layout', 'regions', and 'panes'. The relevant rendered data is stored as
|
|
|
|
|
* the value for each of these keys as it is generated:
|
|
|
|
|
* - 'panes' are an associative array of rendered output, keyed on pane id.
|
|
|
|
|
* - 'regions' are an associative array of rendered output, keyed on region
|
|
|
|
|
* name.
|
|
|
|
|
* - 'layout' is the whole of the rendered output.
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
|
|
|
|
var $rendered = array();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A multilevel array of data prepared for rendering. The first level of the
|
|
|
|
|
* array indicates the type of prepared data. The standard renderer populates
|
|
|
|
|
* and uses two top-level keys, 'panes' and 'regions':
|
|
|
|
|
* - 'panes' are an associative array of pane objects to be rendered, keyed
|
|
|
|
|
* on pane id and sorted into proper rendering order.
|
|
|
|
|
* - 'regions' are an associative array of regions, keyed on region name,
|
|
|
|
|
* each of which is itself an indexed array of pane ids in the order in
|
|
|
|
|
* which those panes appear in that region.
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
|
|
|
|
var $prepared = array();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Boolean state variable, indicating whether or not the prepare() method has
|
|
|
|
|
* been run.
|
|
|
|
|
*
|
|
|
|
|
* This state is checked in panels_renderer_standard::render_layout() to
|
|
|
|
|
* determine whether the prepare method should be automatically triggered.
|
|
|
|
|
*
|
|
|
|
|
* @var bool
|
|
|
|
|
*/
|
|
|
|
|
var $prep_run = FALSE;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The plugin that defines this handler.
|
|
|
|
|
*/
|
|
|
|
|
var $plugin = FALSE;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TRUE if this renderer is rendering in administrative mode
|
|
|
|
|
* which will allow layouts to have extra functionality.
|
|
|
|
|
*
|
|
|
|
|
* @var bool
|
|
|
|
|
*/
|
|
|
|
|
var $admin = FALSE;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Where to add standard meta information. There are three possibilities:
|
|
|
|
|
* - standard: Put the meta information in the normal location. Default.
|
|
|
|
|
* - inline: Put the meta information directly inline. This will
|
|
|
|
|
* not work for javascript.
|
|
|
|
|
*
|
|
|
|
|
* @var string
|
|
|
|
|
*/
|
|
|
|
|
var $meta_location = 'standard';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Include rendered HTML prior to the layout.
|
|
|
|
|
*
|
|
|
|
|
* @var string
|
|
|
|
|
*/
|
|
|
|
|
var $prefix = '';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Include rendered HTML after the layout.
|
|
|
|
|
*
|
|
|
|
|
* @var string
|
|
|
|
|
*/
|
|
|
|
|
var $suffix = '';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Receive and store the display object to be rendered.
|
|
|
|
|
*
|
|
|
|
|
* This is a psuedo-constructor that should typically be called immediately
|
|
|
|
|
* after object construction.
|
|
|
|
|
*
|
|
|
|
|
* @param array $plugin
|
|
|
|
|
* The definition of the renderer plugin.
|
|
|
|
|
* @param panels_display $display
|
|
|
|
|
* The panels display object to be rendered.
|
|
|
|
|
*/
|
|
|
|
|
function init($plugin, &$display) {
|
|
|
|
|
$this->plugin = $plugin;
|
|
|
|
|
$layout = panels_get_layout($display->layout);
|
|
|
|
|
$this->display = &$display;
|
|
|
|
|
$this->plugins['layout'] = $layout;
|
|
|
|
|
if (!isset($layout['regions'])) {
|
|
|
|
|
$this->plugins['layout']['regions'] = panels_get_regions($layout, $display);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (empty($this->plugins['layout'])) {
|
|
|
|
|
watchdog('panels', "Layout: @layout couldn't been found, maybe the theme is disabled.", array('@layout' => $display->layout));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Prepare the attached display for rendering.
|
|
|
|
|
*
|
|
|
|
|
* This is the outermost prepare method. It calls several sub-methods as part
|
|
|
|
|
* of the overall preparation process. This compartmentalization is intended
|
|
|
|
|
* to ease the task of modifying renderer behavior in child classes.
|
|
|
|
|
*
|
|
|
|
|
* If you override this method, it is important that you either call this
|
|
|
|
|
* method via parent::prepare(), or manually set $this->prep_run = TRUE.
|
|
|
|
|
*
|
|
|
|
|
* @param mixed $external_settings
|
|
|
|
|
* An optional parameter allowing external code to pass in additional
|
|
|
|
|
* settings for use in the preparation process. Not used in the default
|
|
|
|
|
* renderer, but included for interface consistency.
|
|
|
|
|
*/
|
|
|
|
|
function prepare($external_settings = NULL) {
|
|
|
|
|
$this->prepare_panes($this->display->content);
|
|
|
|
|
$this->prepare_regions($this->display->panels, $this->display->panel_settings);
|
|
|
|
|
$this->prep_run = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Prepare the list of panes to be rendered, accounting for visibility/access
|
|
|
|
|
* settings and rendering order.
|
|
|
|
|
*
|
|
|
|
|
* This method represents the standard approach for determining the list of
|
|
|
|
|
* panes to be rendered that is compatible with all parts of the Panels
|
|
|
|
|
* architecture. It first applies visibility & access checks, then sorts panes
|
|
|
|
|
* into their proper rendering order, and returns the result as an array.
|
|
|
|
|
*
|
|
|
|
|
* Inheriting classes should override this method if that renderer needs to
|
|
|
|
|
* regularly make additions to the set of panes that will be rendered.
|
|
|
|
|
*
|
|
|
|
|
* @param array $panes
|
|
|
|
|
* An associative array of pane data (stdClass objects), keyed on pane id.
|
|
|
|
|
* @return array
|
|
|
|
|
* An associative array of panes to be rendered, keyed on pane id and sorted
|
|
|
|
|
* into proper rendering order.
|
|
|
|
|
*/
|
|
|
|
|
function prepare_panes($panes) {
|
|
|
|
|
ctools_include('content');
|
|
|
|
|
// Use local variables as writing to them is very slightly faster
|
|
|
|
|
$first = $normal = $last = array();
|
|
|
|
|
|
|
|
|
|
// Prepare the list of panes to be rendered
|
|
|
|
|
foreach ($panes as $pid => $pane) {
|
|
|
|
|
if (empty($this->admin)) {
|
|
|
|
|
// TODO remove in 7.x and ensure the upgrade path weeds out any stragglers; it's been long enough
|
|
|
|
|
$pane->shown = !empty($pane->shown); // guarantee this field exists.
|
|
|
|
|
// If this pane is not visible to the user, skip out and do the next one
|
|
|
|
|
if (!$pane->shown || !panels_pane_access($pane, $this->display)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the pane's subtype is unique, get it so that
|
|
|
|
|
// hook_ctools_content_subtype_alter() and/or
|
|
|
|
|
// hook_ctools_block_info() will be called.
|
|
|
|
|
if ($pane->type != $pane->subtype) {
|
|
|
|
|
$content_type = ctools_content_get_subtype($pane->type, $pane->subtype);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$content_type = ctools_get_content_type($pane->type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If this pane wants to render last, add it to the $last array. We allow
|
|
|
|
|
// this because some panes need to be rendered after other panes,
|
|
|
|
|
// primarily so they can do things like the leftovers of forms.
|
|
|
|
|
if (!empty($content_type['render last'])) {
|
|
|
|
|
$last[$pid] = $pane;
|
|
|
|
|
}
|
|
|
|
|
// If it wants to render first, add it to the $first array. This is used
|
|
|
|
|
// by panes that need to do some processing before other panes are
|
|
|
|
|
// rendered.
|
|
|
|
|
else if (!empty($content_type['render first'])) {
|
|
|
|
|
$first[$pid] = $pane;
|
|
|
|
|
}
|
|
|
|
|
// Otherwise, render it in the normal order.
|
|
|
|
|
else {
|
|
|
|
|
$normal[$pid] = $pane;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$this->prepared['panes'] = $first + $normal + $last;
|
|
|
|
|
|
|
|
|
|
// Allow other modules the alter the prepared panes array.
|
|
|
|
|
drupal_alter('panels_panes_prepared', $this->prepared['panes'], $this);
|
|
|
|
|
|
|
|
|
|
return $this->prepared['panes'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Prepare the list of regions to be rendered.
|
|
|
|
|
*
|
|
|
|
|
* This method is primarily about properly initializing the style plugin that
|
|
|
|
|
* will be used to render the region. This is crucial as regions cannot be
|
|
|
|
|
* rendered without a style plugin (in keeping with Panels' philosophy of
|
|
|
|
|
* hardcoding none of its output), but for most regions no style has been
|
|
|
|
|
* explicitly set. The logic here is what accommodates that situation:
|
|
|
|
|
* - If a region has had its style explicitly set, then we fetch that plugin
|
|
|
|
|
* and continue.
|
|
|
|
|
* - If the region has no explicit style, but a style was set at the display
|
|
|
|
|
* level, then inherit the style from the display.
|
|
|
|
|
* - If neither the region nor the dispay have explicitly set styles, then
|
|
|
|
|
* fall back to the hardcoded 'default' style, a very minimal style.
|
|
|
|
|
*
|
|
|
|
|
* The other important task accomplished by this method is ensuring that even
|
|
|
|
|
* regions without any panes are still properly prepared for the rendering
|
|
|
|
|
* process. This is essential because the way Panels loads display objects
|
|
|
|
|
* (@see panels_load_displays) results only in a list of regions that
|
|
|
|
|
* contain panes - not necessarily all the regions defined by the layout
|
|
|
|
|
* plugin, which can only be determined by asking the plugin at runtime. This
|
|
|
|
|
* method consults that retrieved list of regions and prepares all of those,
|
|
|
|
|
* ensuring none are inadvertently skipped.
|
|
|
|
|
*
|
|
|
|
|
* @param array $region_pane_list
|
|
|
|
|
* An associative array of pane ids, keyed on the region to which those pids
|
|
|
|
|
* are assigned. In the default case, this is $display->panels.
|
|
|
|
|
* @param array $settings
|
|
|
|
|
* All known region style settings, including both the top-level display's
|
|
|
|
|
* settings (if any) and all region-specific settings (if any).
|
|
|
|
|
* @return array
|
|
|
|
|
* An array of regions prepared for rendering.
|
|
|
|
|
*/
|
|
|
|
|
function prepare_regions($region_pane_list, $settings) {
|
|
|
|
|
// Initialize defaults to be used for regions without their own explicit
|
|
|
|
|
// settings. Use display settings if they exist, else hardcoded defaults.
|
|
|
|
|
$default = array(
|
|
|
|
|
'style' => panels_get_style(!empty($settings['style']) ? $settings['style'] : 'default'),
|
|
|
|
|
'style settings' => isset($settings['style_settings']['default']) ? $settings['style_settings']['default'] : array(),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$regions = array();
|
|
|
|
|
if (empty($settings)) {
|
|
|
|
|
// No display/panel region settings exist, init all with the defaults.
|
|
|
|
|
foreach ($this->plugins['layout']['regions'] as $region_id => $title) {
|
|
|
|
|
// Ensure this region has at least an empty panes array.
|
|
|
|
|
$panes = !empty($region_pane_list[$region_id]) ? $region_pane_list[$region_id] : array();
|
|
|
|
|
|
|
|
|
|
$regions[$region_id] = $default;
|
|
|
|
|
$regions[$region_id]['pids'] = $panes;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Some settings exist; iterate through each region and set individually.
|
|
|
|
|
foreach ($this->plugins['layout']['regions'] as $region_id => $title) {
|
|
|
|
|
// Ensure this region has at least an empty panes array.
|
|
|
|
|
$panes = !empty($region_pane_list[$region_id]) ? $region_pane_list[$region_id] : array();
|
|
|
|
|
if (empty($settings[$region_id]['style']) || $settings[$region_id]['style'] == -1) {
|
|
|
|
|
$regions[$region_id] = $default;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$regions[$region_id]['style'] = panels_get_style($settings[$region_id]['style']);
|
|
|
|
|
$regions[$region_id]['style settings'] = isset($settings['style_settings'][$region_id]) ? $settings['style_settings'][$region_id] : array();
|
|
|
|
|
}
|
|
|
|
|
$regions[$region_id]['pids'] = $panes;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->prepared['regions'] = $regions;
|
|
|
|
|
return $this->prepared['regions'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Build inner content, then hand off to layout-specified theme function for
|
|
|
|
|
* final render step.
|
|
|
|
|
*
|
|
|
|
|
* This is the outermost method in the Panels render pipeline. It calls the
|
|
|
|
|
* inner methods, which return a content array, which is in turn passed to the
|
|
|
|
|
* theme function specified in the layout plugin.
|
|
|
|
|
*
|
|
|
|
|
* @return string
|
|
|
|
|
* Themed & rendered HTML output.
|
|
|
|
|
*/
|
|
|
|
|
function render() {
|
|
|
|
|
// Let the display refer back to the renderer.
|
|
|
|
|
$this->display->renderer_handler = $this;
|
|
|
|
|
|
|
|
|
|
// Attach out-of-band data first.
|
|
|
|
|
$this->add_meta();
|
|
|
|
|
|
|
|
|
|
if (empty($this->display->cache['method']) || !empty($this->display->skip_cache)) {
|
|
|
|
|
return $this->render_layout();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$cache = panels_get_cached_content($this->display, $this->display->args, $this->display->context);
|
|
|
|
|
if ($cache === FALSE) {
|
|
|
|
|
$cache = new panels_cache_object();
|
|
|
|
|
$cache->set_content($this->render_layout());
|
|
|
|
|
panels_set_cached_content($cache, $this->display, $this->display->args, $this->display->context);
|
|
|
|
|
}
|
|
|
|
|
return $cache->content;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Perform display/layout-level render operations.
|
|
|
|
|
*
|
|
|
|
|
* This method triggers all the inner pane/region rendering processes, passes
|
|
|
|
|
* that to the layout plugin's theme callback, and returns the rendered HTML.
|
|
|
|
|
*
|
|
|
|
|
* If display-level caching is enabled and that cache is warm, this method
|
|
|
|
|
* will not be called.
|
|
|
|
|
*
|
|
|
|
|
* @return string
|
|
|
|
|
* The HTML string representing the entire rendered, themed panel.
|
|
|
|
|
*/
|
|
|
|
|
function render_layout() {
|
|
|
|
|
if (empty($this->prep_run)) {
|
|
|
|
|
$this->prepare();
|
|
|
|
|
}
|
|
|
|
|
$this->render_panes();
|
|
|
|
|
$this->render_regions();
|
|
|
|
|
|
|
|
|
|
if ($this->admin && !empty($this->plugins['layout']['admin theme'])) {
|
|
|
|
|
$theme = $this->plugins['layout']['admin theme'];
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$theme = $this->plugins['layout']['theme'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$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));
|
|
|
|
|
return $this->prefix . $this->rendered['layout'] . $this->suffix;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Attach out-of-band page metadata (e.g., CSS and JS).
|
|
|
|
|
*
|
|
|
|
|
* This must be done before render, because panels-within-panels must have
|
|
|
|
|
* their CSS added in the right order: inner content before outer content.
|
|
|
|
|
*/
|
|
|
|
|
function add_meta() {
|
|
|
|
|
if (!empty($this->plugins['layout']['css'])) {
|
|
|
|
|
if (file_exists(path_to_theme() . '/' . $this->plugins['layout']['css'])) {
|
|
|
|
|
$this->add_css(path_to_theme() . '/' . $this->plugins['layout']['css']);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$this->add_css($this->plugins['layout']['path'] . '/' . $this->plugins['layout']['css']);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($this->admin && isset($this->plugins['layout']['admin css'])) {
|
|
|
|
|
$this->add_css($this->plugins['layout']['path'] . '/' . $this->plugins['layout']['admin css']);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add CSS information to the renderer.
|
|
|
|
|
*
|
|
|
|
|
* To facilitate previews over Views, CSS can now be added in a manner
|
|
|
|
|
* that does not necessarily mean just using drupal_add_css. Therefore,
|
|
|
|
|
* during the panel rendering process, this method can be used to add
|
|
|
|
|
* css and make certain that ti gets to the proper location.
|
|
|
|
|
*
|
|
|
|
|
* The arguments should exactly match drupal_add_css().
|
|
|
|
|
*
|
|
|
|
|
* @see drupal_add_css
|
|
|
|
|
*/
|
|
|
|
|
function add_css($filename) {
|
|
|
|
|
switch ($this->meta_location) {
|
|
|
|
|
case 'standard':
|
|
|
|
|
drupal_add_css($filename);
|
|
|
|
|
break;
|
|
|
|
|
case 'inline':
|
|
|
|
|
$url = base_path() . $filename;
|
|
|
|
|
$this->prefix .= '<link type="text/css" rel="stylesheet" href="' . file_create_url($url) . '" />'."\n";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Render all prepared panes, first by dispatching to their plugin's render
|
|
|
|
|
* callback, then handing that output off to the pane's style plugin.
|
|
|
|
|
*
|
|
|
|
|
* @return array
|
|
|
|
|
* The array of rendered panes, keyed on pane pid.
|
|
|
|
|
*/
|
|
|
|
|
function render_panes() {
|
|
|
|
|
ctools_include('content');
|
|
|
|
|
|
|
|
|
|
// First, render all the panes into little boxes.
|
|
|
|
|
$this->rendered['panes'] = array();
|
|
|
|
|
foreach ($this->prepared['panes'] as $pid => $pane) {
|
|
|
|
|
$content = $this->render_pane($pane);
|
|
|
|
|
if ($content) {
|
|
|
|
|
$this->rendered['panes'][$pid] = $content;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $this->rendered['panes'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Render a pane using its designated style.
|
|
|
|
|
*
|
|
|
|
|
* This method also manages 'title pane' functionality, where the title from
|
|
|
|
|
* an individual pane can be bubbled up to take over the title for the entire
|
|
|
|
|
* display.
|
|
|
|
|
*
|
|
|
|
|
* @param stdClass $pane
|
|
|
|
|
* A Panels pane object, as loaded from the database.
|
|
|
|
|
*/
|
|
|
|
|
function render_pane(&$pane) {
|
|
|
|
|
$content = $this->render_pane_content($pane);
|
|
|
|
|
if ($this->display->hide_title == PANELS_TITLE_PANE && !empty($this->display->title_pane) && $this->display->title_pane == $pane->pid) {
|
|
|
|
|
|
|
|
|
|
// If the user selected to override the title with nothing, and selected
|
|
|
|
|
// this as the title pane, assume the user actually wanted the original
|
|
|
|
|
// title to bubble up to the top but not actually be used on the pane.
|
|
|
|
|
if (empty($content->title) && !empty($content->original_title)) {
|
|
|
|
|
$this->display->stored_pane_title = $content->original_title;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$this->display->stored_pane_title = !empty($content->title) ? $content->title : '';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!empty($content->content)) {
|
|
|
|
|
if (!empty($pane->style['style'])) {
|
|
|
|
|
$style = panels_get_style($pane->style['style']);
|
|
|
|
|
|
|
|
|
|
if (isset($style) && isset($style['render pane'])) {
|
|
|
|
|
$output = theme($style['render pane'], array('content' => $content, 'pane' => $pane, 'display' => $this->display, 'style' => $style, 'settings' => $pane->style['settings']));
|
|
|
|
|
|
|
|
|
|
// This could be null if no theme function existed.
|
|
|
|
|
if (isset($output)) {
|
|
|
|
|
return $output;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fallback
|
|
|
|
|
return theme('panels_pane', array('content' => $content, 'pane' => $pane, 'display' => $this->display));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Render the interior contents of a single pane.
|
|
|
|
|
*
|
|
|
|
|
* This method retrieves pane content and produces a ready-to-render content
|
|
|
|
|
* object. It also manages pane-specific caching.
|
|
|
|
|
*
|
|
|
|
|
* @param stdClass $pane
|
|
|
|
|
* A Panels pane object, as loaded from the database.
|
|
|
|
|
* @return stdClass $content
|
|
|
|
|
* A renderable object, containing a subject, content, etc. Based on the
|
|
|
|
|
* renderable objects used by the block system.
|
|
|
|
|
*/
|
|
|
|
|
function render_pane_content(&$pane) {
|
|
|
|
|
ctools_include('context');
|
|
|
|
|
// TODO finally safe to remove this check?
|
|
|
|
|
if (!is_array($this->display->context)) {
|
|
|
|
|
watchdog('panels', 'renderer::render_pane_content() hit with a non-array for the context', $this->display, WATCHDOG_DEBUG);
|
|
|
|
|
$this->display->context = array();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$content = FALSE;
|
|
|
|
|
$caching = !empty($pane->cache['method']) && empty($this->display->skip_cache);
|
|
|
|
|
if ($caching && ($cache = panels_get_cached_content($this->display, $this->display->args, $this->display->context, $pane))) {
|
|
|
|
|
$content = $cache->content;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if ($caching) {
|
|
|
|
|
// This is created before rendering so that calls to drupal_add_js
|
|
|
|
|
// and drupal_add_css will be captured.
|
|
|
|
|
$cache = new panels_cache_object();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$content = ctools_content_render($pane->type, $pane->subtype, $pane->configuration, array(), $this->display->args, $this->display->context);
|
|
|
|
|
|
|
|
|
|
if (empty($content)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (module_implements('panels_pane_content_alter') as $module) {
|
|
|
|
|
$function = $module . '_panels_pane_content_alter';
|
|
|
|
|
$function($content, $pane, $this->display->args, $this->display->context, $this, $this->display);
|
|
|
|
|
}
|
|
|
|
|
if ($caching && isset($cache)) {
|
|
|
|
|
$cache->set_content($content);
|
|
|
|
|
panels_set_cached_content($cache, $this->display, $this->display->args, $this->display->context, $pane);
|
|
|
|
|
$content = $cache->content;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Pass long the css_id that is usually available.
|
|
|
|
|
if (!empty($pane->css['css_id'])) {
|
|
|
|
|
$content->css_id = check_plain($pane->css['css_id']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Pass long the css_class that is usually available.
|
|
|
|
|
if (!empty($pane->css['css_class'])) {
|
|
|
|
|
$content->css_class = check_plain($pane->css['css_class']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $content;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Render all prepared regions, placing already-rendered panes into their
|
|
|
|
|
* appropriate positions therein.
|
|
|
|
|
*
|
|
|
|
|
* @return array
|
|
|
|
|
* An array of rendered panel regions, keyed on the region name.
|
|
|
|
|
*/
|
|
|
|
|
function render_regions() {
|
|
|
|
|
$this->rendered['regions'] = array();
|
|
|
|
|
|
|
|
|
|
// Loop through all panel regions, put all panes that belong to the current
|
|
|
|
|
// region in an array, then render the region. Primarily this ensures that
|
|
|
|
|
// the panes are arranged in the proper order.
|
|
|
|
|
$content = array();
|
|
|
|
|
foreach ($this->prepared['regions'] as $region_id => $conf) {
|
|
|
|
|
$region_panes = array();
|
|
|
|
|
foreach ($conf['pids'] as $pid) {
|
|
|
|
|
// Only include panes for region rendering if they had some output.
|
|
|
|
|
if (!empty($this->rendered['panes'][$pid])) {
|
|
|
|
|
$region_panes[$pid] = $this->rendered['panes'][$pid];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$this->rendered['regions'][$region_id] = $this->render_region($region_id, $region_panes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->rendered['regions'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Render a single panel region.
|
|
|
|
|
*
|
|
|
|
|
* Primarily just a passthrough to the panel region rendering callback
|
|
|
|
|
* specified by the style plugin that is attached to the current panel region.
|
|
|
|
|
*
|
|
|
|
|
* @param $region_id
|
|
|
|
|
* The ID of the panel region being rendered
|
|
|
|
|
* @param $panes
|
|
|
|
|
* An array of panes that are assigned to the panel that's being rendered.
|
|
|
|
|
*
|
|
|
|
|
* @return string
|
|
|
|
|
* The rendered, HTML string output of the passed-in panel region.
|
|
|
|
|
*/
|
|
|
|
|
function render_region($region_id, $panes) {
|
|
|
|
|
$style = $this->prepared['regions'][$region_id]['style'];
|
|
|
|
|
$style_settings = $this->prepared['regions'][$region_id]['style settings'];
|
|
|
|
|
|
|
|
|
|
// Retrieve the pid (can be a panel page id, a mini panel id, etc.), this
|
|
|
|
|
// might be used (or even necessary) for some panel display styles.
|
|
|
|
|
// TODO: Got to fix this to use panel page name instead of pid, since pid is
|
|
|
|
|
// no longer guaranteed. This needs an API to be able to set the final id.
|
|
|
|
|
$owner_id = 0;
|
|
|
|
|
if (isset($this->display->owner) && is_object($this->display->owner) && isset($this->display->owner->id)) {
|
|
|
|
|
$owner_id = $this->display->owner->id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$output = theme($style['render region'], array('display' => $this->display, 'owner_id' => $owner_id, 'panes' => $panes, 'settings' => $style_settings, 'region_id' => $region_id, 'style' => $style));
|
|
|
|
|
return $output;
|
|
|
|
|
}
|
|
|
|
|
}
|