panels.module in Panels 6.2
Same filename and directory in other branches
Core functionality for the Panels engine.
File
panels.moduleView source
<?php
/**
* @file panels.module
*
* Core functionality for the Panels engine.
*/
/**
* Error code bitmask used for identifying argument behavior at runtime.
*/
define('PANELS_ARG_IS_BAD', 1);
define('PANELS_ARG_USE_FALLBACK', 1 << 1);
/**
* Returns the API version of Panels. This didn't exist in 1.
*
* @return An array with the major and minor versions
*/
function panels_api_version() {
return array(
2,
0,
);
}
function panels_theme() {
$theme = array();
$theme['panels_layout_link'] = array(
'arguments' => array(
'title',
'id',
'image',
'link',
),
);
$theme['panels_layout_icon'] = array(
'arguments' => array(
'id',
'image',
'title' => NULL,
),
);
$theme['panels_imagebutton'] = array(
'arguments' => array(
'element',
),
);
$theme['panels_edit_display_form'] = array(
'arguments' => array(
'form',
),
'file' => 'includes/display-edit.inc',
);
$theme['panels_edit_layout_form_choose'] = array(
'arguments' => array(
'form',
),
'file' => 'includes/display-edit.inc',
);
$theme['panels_pane'] = array(
'arguments' => array(
'content',
'pane',
'display',
),
'file' => 'includes/display-render.inc',
);
$theme['panels_common_content_list'] = array(
'arguments' => array(
'display',
),
'file' => 'includes/common.inc',
);
$theme['panels_common_context_list'] = array(
'arguments' => array(
'object',
),
'file' => 'includes/common.inc',
);
$theme['panels_common_context_item_form'] = array(
'arguments' => array(
'form',
),
'file' => 'includes/common.inc',
);
$theme['panels_common_context_item_row'] = array(
'arguments' => array(
'type',
'form',
'position',
'count',
'with_tr' => TRUE,
),
'file' => 'includes/common.inc',
);
$theme['panels_dnd'] = array(
'arguments' => array(
'content',
),
'file' => 'includes/display-edit.inc',
'function' => 'theme_panels_dnd',
);
$theme['panels_panel_dnd'] = array(
'arguments' => array(
'content',
'area',
'label',
'footer',
),
'file' => 'includes/display-edit.inc',
'function' => 'theme_panels_panel_dnd',
);
$theme['panels_pane_dnd'] = array(
'arguments' => array(
'block',
'id',
'label',
'left_buttons' => NULL,
'buttons' => NULL,
),
'file' => 'includes/display-edit.inc',
);
$theme['panels_pane_collapsible'] = array(
'arguments' => array(
'block',
),
'file' => 'includes/display-edit.inc',
);
$theme['profile_fields_pane'] = array(
'arguments' => array(
'category' => NULL,
'vars' => NULL,
),
'template' => 'content_types/profile_fields_pane',
);
// Register layout and style themes on behalf of all of these items.
panels_load_include('plugins');
// No need to worry about files; the plugin has to already be loaded for us
// to even know what the theme function is, so files will be auto included.
$layouts = panels_get_layouts();
foreach ($layouts as $name => $data) {
if (!empty($data['theme'])) {
$theme[$data['theme']] = array(
'arguments' => array(
'css_id' => NULL,
'content' => NULL,
'settings' => NULL,
),
'path' => $data['path'],
);
// if no theme function exists, assume template.
if (!function_exists("theme_{$data['theme']}")) {
$theme[$data['theme']]['template'] = str_replace('_', '-', $data['theme']);
}
}
}
$styles = panels_get_styles();
foreach ($styles as $name => $data) {
if (!empty($data['render pane'])) {
$theme[$data['render pane']] = array(
'arguments' => array(
'content' => NULL,
'pane' => NULL,
'display' => NULL,
),
);
}
if (!empty($data['render panel'])) {
$theme[$data['render panel']] = array(
'arguments' => array(
'display' => NULL,
'panel_id' => NULL,
'panes' => NULL,
'settings' => NULL,
),
);
}
}
return $theme;
}
/**
* Implementation of hook_menu
*/
function panels_menu() {
$items = array();
// Provide some common options to reduce code repetition.
// By using array addition and making sure these are the rightmost
// value, they won't override anything already set.
$base = array(
'access arguments' => array(
'access content',
),
'type' => MENU_CALLBACK,
'file' => 'includes/display-edit.inc',
);
$items['panels/ajax/add-pane'] = array(
'page callback' => 'panels_ajax_add_pane_choose',
) + $base;
$items['panels/ajax/add-pane-config'] = array(
'page callback' => 'panels_ajax_add_pane_config',
) + $base;
$items['panels/ajax/configure'] = array(
'page callback' => 'panels_ajax_configure_pane',
) + $base;
$items['panels/ajax/show'] = array(
'page callback' => 'panels_ajax_toggle_shown',
'page arguments' => array(
'show',
),
) + $base;
$items['panels/ajax/hide'] = array(
'page callback' => 'panels_ajax_toggle_shown',
'page arguments' => array(
'hide',
),
) + $base;
$items['panels/ajax/cache-method'] = array(
'page callback' => 'panels_ajax_cache_method',
) + $base;
$items['panels/ajax/cache-settings'] = array(
'page callback' => 'panels_ajax_cache_settings',
) + $base;
// For panel settings on the edit layout settings page
$items['panels/ajax/style-settings'] = array(
'page callback' => 'panels_ajax_style_settings',
'file' => 'includes/display-layout-settings.inc',
) + $base;
// Non-display editor callbacks
$items['panels/node/autocomplete'] = array(
'title' => 'Autocomplete node',
'page callback' => 'panels_node_autocomplete',
'file' => 'includes/callbacks.inc',
) + $base;
// For context add/configure calls in common-context.inc
$items['panels/ajax/context-add'] = array(
'page callback' => 'panels_ajax_context_item_add',
'file' => 'includes/common-context.inc',
) + $base;
$items['panels/ajax/context-configure'] = array(
'page callback' => 'panels_ajax_context_item_edit',
'file' => 'includes/common-context.inc',
) + $base;
$items['panels/ajax/context-delete'] = array(
'page callback' => 'panels_ajax_context_item_delete',
'file' => 'includes/common-context.inc',
) + $base;
// Provide a nice location for a panels admin panel.
$items['admin/panels'] = array(
'title' => 'Panels',
'access arguments' => array(
'access administration pages',
),
'page callback' => 'panels_admin_page',
'file' => 'includes/callbacks.inc',
'description' => 'Administer items related to the Panels module.',
);
return $items;
}
/**
* Implementation of hook_init()
*/
function panels_init() {
drupal_add_css(panels_get_path('css/panels.css'));
drupal_add_js(panels_get_path('js/panels.js'));
}
/**
* Load a panels include file.
*/
function panels_load_include($include, $path = 'includes/') {
static $loaded = array();
if (empty($loaded["{$path}{$include}.inc"])) {
require_once './' . panels_get_path("{$path}{$include}.inc");
$loaded["{$path}{$include}.inc"] = TRUE;
}
}
/**
* panels path helper function
*/
function panels_get_path($file, $base_path = FALSE, $module = 'panels') {
$output = $base_path ? base_path() : '';
return $output . drupal_get_path('module', $module) . '/' . $file;
}
/**
* Implementation of hook_perm
*/
function panels_perm() {
return array(
'view all panes',
'view pane admin links',
'administer pane visibility',
'administer pane access',
'administer advanced pane settings',
'use panels caching features',
);
}
/**
* Get an object from cache.
*/
function panels_cache_get($obj, $did, $skip_cache = FALSE) {
static $cache = array();
$key = "{$obj}:{$did}";
if ($skip_cache) {
unset($cache[$key]);
}
if (!array_key_exists($key, $cache)) {
$data = db_fetch_object(db_query("SELECT * FROM {panels_object_cache} WHERE sid = '%s' AND obj = '%s' AND did = %d", session_id(), $obj, $did));
if ($data) {
$cache[$key] = unserialize($data->data);
}
}
return isset($cache[$key]) ? $cache[$key] : NULL;
}
/**
* Save the edited object into the cache.
*/
function panels_cache_set($obj, $did, $cache) {
panels_cache_clear($obj, $did);
db_query("INSERT INTO {panels_object_cache} (sid, obj, did, data, timestamp) VALUES ('%s', '%s', %d, '%s', %d)", session_id(), $obj, $did, serialize($cache), time());
}
/**
* Clear a object from the cache; used if the editing is aborted.
*/
function panels_cache_clear($obj, $did) {
db_query("DELETE FROM {panels_object_cache} WHERE sid = '%s' AND obj = '%s' AND did = %d", session_id(), $obj, $did);
}
/**
* Implementation of hook_cron. Clean up old caches.
*/
function panels_cron() {
// delete anything 7 days old or more.
db_query("DELETE FROM {panels_object_cache} WHERE timestamp < %d", time() - 86400 * 7);
}
// ---------------------------------------------------------------------------
// panels display editing
/**
* @defgroup mainapi Functions comprising the main panels API
* @{
*/
/**
* Main API entry point to edit a panel display.
*
* Sample implementations utiltizing the the complex $destination behavior can be found
* in panels_page_edit_content() and, in a separate contrib module, OG Blueprints
* (http://drupal.org/project/og_blueprints), og_blueprints_blueprint_edit().
*
* @ingroup mainapi
*
* @param object $display instanceof panels_display \n
* A fully loaded panels $display object, as returned from panels_load_display().
* Merely passing a did is NOT sufficient. \n
* Note that 'fully loaded' means the $display must already be loaded with any contexts
* the caller wishes to have set for the display.
* @param mixed $destination \n
* The redirect destination that the user should be taken to on form submission or
* cancellation. With panels_edit, $destination has complex effects on the return
* values of panels_edit() once the form has been submitted. See the explanation of
* the return value below to understand the different types of values returned by panels_edit()
* at different stages of FAPI. Under most circumstances, simply passing in
* drupal_get_destination() is all that's necessary.
* @param array $content_types \n
* An associative array of allowed content types, typically as returned from
* panels_common_get_allowed_types(). Note that context partially governs available content types,
* so you will want to create any relevant contexts using panels_create_context() or
* panels_create_context_empty() to make sure all the appropriate content types are available.
*
* @return
* Because the functions called by panels_edit() invoke the form API, this function
* returns different values depending on the stage of form submission we're at. In Drupal 5,
* the phase of form submission is indicated by the contents of $_POST['op']. Here's what you'll
* get at different stages:
* -# If !$_POST['op']: then we're on on the initial passthrough and the form is being
* rendered, so it's the $form itself that's being returned. Because negative margins,
* a common CSS technique, bork the display editor's ajax drag-and-drop, it's important
* that the $output be printed, not returned. Use this syntax in the caller function: \n
* print theme('page', panels_edit($display, $destination, $content_types), FALSE); \n
* -# If $_POST['op'] == t('Cancel'): form submission has been cancelled. If empty($destination) == FALSE,
* then there is no return value and the panels API takes care of redirecting to $destination.
* If empty($destination) == TRUE, then there's still no return value, but the caller function
* has to take care of form redirection.
* -# If $_POST['op'] == ('Save'): the form has been submitted successfully and has run through
* panels_edit_display_submit(). $output depends on the value of $destination:
* - If empty($destination) == TRUE: $output contains the modified $display
* object, and no redirection will occur. This option is useful if the caller
* needs to perform additional operations on or with the modified $display before
* the page request is complete. Using hook_form_alter() to add an additional submit
* handler is typically the preferred method for something like this, but there
* are certain use cases where that is infeasible and $destination = NULL should
* be used instead. If this method is employed, the caller will need to handle form
* redirection. Note that having $_REQUEST['destination'] set, whether via
* drupal_get_destination() or some other method, will NOT interfere with this
* functionality; consequently, you can use drupal_get_destination() to safely store
* your desired redirect in the caller function, then simply use drupal_goto() once
* panels_edit() has done its business.
* - If empty($destination) == FALSE: the form will redirect to the URL string
* given in $destination and NO value will be returned.
*/
function panels_edit($display, $destination = NULL, $content_types = NULL) {
panels_load_include('display-edit');
panels_load_include('ajax');
panels_load_include('plugins');
return _panels_edit($display, $destination, $content_types);
}
/**
* API entry point for selecting a layout for a given display.
*
* Layout selection is nothing more than a list of radio items encompassing the available
* layouts for this display, as defined by .inc files in the panels/layouts subdirectory.
* The only real complexity occurs when a user attempts to change the layout of a display
* that has some content in it.
*
* @param object $display instanceof panels_display \n
* A fully loaded panels $display object, as returned from panels_load_display().
* Merely passing a did is NOT sufficient.
* @param string $finish
* A string that will be used for the text of the form submission button. If no value is provided,
* then the form submission button will default to t('Save').
* @param mixed $destination
* Basic usage is a string containing the URL that the form should redirect to upon submission.
* For a discussion of advanced usages, see panels_edit().
* @param mixed $allowed_layouts
* Allowed layouts has three different behaviors that depend on which of three value types
* are passed in by the caller:
* #- if $allowed_layouts instanceof panels_allowed_layouts (includes subclasses): the most
* complex use of the API. The caller is passing in a loaded panels_allowed_layouts object
* that the client module previously created and stored somewhere using a custom storage
* mechanism.
* #- if is_string($allowed_layouts): the string will be used in a call to variable_get() which
* will call the $allowed_layouts . '_allowed_layouts' var. If the data was stored properly
* in the system var, the $allowed_layouts object will be unserialized and recreated.
* @see panels_common_set_allowed_layouts()
* #- if is_null($allowed_layouts): the default behavior, which also provides backwards
* compatibility for implementations of the Panels2 API written before beta4. In this case,
* a dummy panels_allowed_layouts object is created which does not restrict any layouts.
* Subsequent behavior is indistinguishable from pre-beta4 behavior.
*
* @return
* Can return nothing, or a modified $display object, or a redirection string; return values for the
* panels_edit* family of functions are quite complex. See panels_edit() for detailed discussion.
* @see panels_edit()
*/
function panels_edit_layout($display, $finish, $destination = NULL, $allowed_layouts = NULL) {
panels_load_include('display-layout');
panels_load_include('plugins');
return _panels_edit_layout($display, $finish, $destination, $allowed_layouts);
}
/**
* API entry point for configuring the layout settings for a given display.
*
* For all layouts except Flexible, the layout settings form allows the user to select styles,
* as defined by .inc files in the panels/styles subdirectory, for the panels in their display.
* For the Flexible layout, the layout settings form allows the user to provide dimensions
* for their flexible layout in addition to applying styles to panels.
*
* @param object $display instanceof panels_display \n
* A fully loaded panels $display object, as returned from panels_load_display().
* Merely passing a did is NOT sufficient.
* @param string $finish
* A string that will be used for the text of (one of) the form submission button(s). Note that
* panels will NOT wrap $finish in t() for you, so your caller should make sure to do so. \n
* The submit behavior of the form is primarily governed by the value of $destination (see
* below), but is secondarily governed by $finish as follows:
* -# If $finish != t('Save'), then two #submit buttons will be present: one with the button
* text t('Save'), and the other with the button text $finish. .
* - Clicking the 'Save' button will save any changes on the form to the $display object and
* keep the user on the same editing page.
* - Clicking the $finish button will also save the $display object, but the user will be
* redirected to the URL specified in $destination.
* -# If $finish == t('Save'), then there is only one button, still called t('Save'), but it
* mimics the behavior of the $finish button above by redirecting the user away from the form.
* @param mixed $destination
* Basic usage is a string containing the URL that the form should redirect to upon submission.
* For a discussion of advanced usages that rely on NULL values for $destination, see the
* panels_edit() documentation.
* @param mixed $title
* The $title variable has three modes of operation:
* -# If $title == FALSE (the default), then no widget will appear on the panels_edit_layout_settings form
* allowing the user to select a title, and other means for setting page titles will take precedent. If
* no other means are used to provide a title, then the title will be hidden when rendering the $display.
* -# If $title == TRUE, then two widgets will appear on the panels_edit_layout_settings form allowing the
* user to input a title specific to this $display, as well as a checkbox enabling the user to disable
* page titles entirely for this $display object.
* -# If $title == (string), then the behavior is very similar to mode 2, but the widget description
* on the title textfield will indicate that the $title string will be used as the default page title
* if none is provided on this form. When utilizing this option, note that the panels API can only
* provide the data for these values; you must implement the appropriate conditionals to make it true.
*
* @return
* Can return nothing, or a modified $display object, or a redirection string; return values for the
* panels_edit* family of functions are quite complex. See panels_edit() for detailed discussion.
* @see panels_edit()
*/
function panels_edit_layout_settings($display, $finish, $destination = NULL, $title = FALSE) {
panels_load_include('display-layout-settings');
panels_load_include('ajax');
panels_load_include('plugins');
return _panels_edit_layout_settings($display, $finish, $destination, $title);
}
// ---------------------------------------------------------------------------
// panels database functions
/**
* Forms the basis of a panel display
*
*/
class panels_display {
var $args = array();
var $content = array();
var $panels = array();
var $incoming_content = NULL;
var $css_id = NULL;
var $context = array();
var $layout_settings = array();
var $panel_settings = array();
var $cache = array();
var $title = '';
var $hide_title = 0;
var $layout = '';
function add_pane($pane, $location = FALSE) {
$pane->pid = $this
->next_new_pid();
if (!$location || !isset($this->panels[$location])) {
foreach ($this->panels as $panel_name => $panel) {
if (array_key_exists($pane->pid, $panel)) {
$this->panels[$panel_name][] = $pane->pid;
}
}
}
else {
$this->panels[$location][] = $pane->pid;
}
}
function duplicate_pane($pid, $location = FALSE) {
$pane = $this
->clone_pane($pid);
$this
->add_pane($pane, $location);
}
function clone_pane($pid) {
$pane = drupal_clone($this->content[$pid]);
foreach (array_keys($this->content) as $pidcheck) {
// necessary?
unset($pane->position);
}
return $pane;
}
function next_new_pid() {
// necessary if/until we use this method and ONLY this method for adding temporary pids.
// then we can do it with a nice static var.
$id = array(
0,
);
foreach (array_keys($this->content) as $pid) {
if (!is_numeric($pid)) {
$id[] = substr($pid, 4);
}
}
$next_id = end($id);
return ++$next_id;
}
}
/**
* }@ End of 'defgroup mainapi', although other functions are specifically added later
*/
function panels_export_pane_across_displays($source_display, &$target_display, $pid, $location = FALSE) {
$pane = $source_display
->clone_pane($pid);
$target_display
->add_pane($pane, $location);
}
/**
* Clean up a display object and add some required information, if missing.
*
* Currently a display object needs 'args', 'incoming content', 'context'
* and a 'css_id'.
*
* @param &$display
* The display object to be sanitized.
* @return
* The sanitized display object.
*/
function panels_sanitize_display(&$display) {
if (!isset($display->args)) {
$display->args = array();
}
if (!isset($display->incoming_content)) {
$display->incoming_content = NULL;
}
if (!isset($display->context)) {
$display->context = array();
}
if (!isset($display->css_id)) {
$display->css_id = NULL;
}
}
/**
* Creates a new display, setting the ID to our magic new id.
*/
function panels_new_display() {
$display = new panels_display();
$display->did = 'new';
return $display;
}
function panels_new_pane($type, $subtype) {
$pane = new stdClass();
$pane->pid = 'new';
$pane->type = $type;
$pane->subtype = $subtype;
$pane->configuration = array();
$pane->access = array();
$pane->shown = TRUE;
$pane->visibility = '';
return $pane;
}
/**
* Load and fill the requested $display object(s).
*
* Helper function primarily for for panels_load_display().
*
* @param array $dids
* An indexed array of dids to be loaded from the database.
*
* @return $displays
* An array of displays, keyed by their display dids.
*/
function panels_load_displays($dids) {
$displays = array();
if (empty($dids) || !is_array($dids)) {
return $displays;
}
$result = db_query("SELECT * FROM {panels_display} WHERE did IN (" . db_placeholders($dids) . ")", $dids);
while ($obj = db_fetch_array($result)) {
$display = new panels_display();
foreach ($obj as $key => $value) {
$display->{$key} = $value;
// unserialize important bits
if (in_array($key, array(
'layout_settings',
'panel_settings',
'cache',
))) {
$display->{$key} = empty($display->{$key}) ? array() : unserialize($display->{$key});
}
}
$display->panels = $display->content = array();
$displays[$display->did] = $display;
}
foreach (module_implements('panels_layout_content_alter') as $module) {
$function = $module . '_panels_layout_content_alter';
$function($content, $layout, $settings);
}
$result = db_query("SELECT * FROM {panels_pane} WHERE did IN (" . db_placeholders($dids) . ") ORDER BY did, panel, position", $dids);
while ($pane = db_fetch_object($result)) {
$pane->configuration = unserialize($pane->configuration);
$pane->cache = empty($pane->cache) ? array() : unserialize($pane->cache);
$pane->access = $pane->access ? explode(', ', $pane->access) : array();
// Old panels may not have shown property, so enable by default when loading.
$pane->shown = isset($pane->shown) ? $pane->shown : TRUE;
$displays[$pane->did]->panels[$pane->panel][] = $pane->pid;
$displays[$pane->did]->content[$pane->pid] = $pane;
}
return $displays;
}
/**
* Load a single display.
*
* @ingroup mainapi
*
* @param int $did
* The display id (did) of the display to be loaded.
*
* @return object $display instanceof panels_display \n
* Returns a partially-loaded panels_display object. $display objects returned from
* from this function have only the following data:
* - $display->did (the display id)
* - $display->name (the 'name' of the display, where applicable - it often isn't)
* - $display->layout (a string with the system name of the display's layout)
* - $display->panel_settings (custom layout style settings contained in an associative array; NULL if none)
* - $display->layout_settings (panel size and configuration settings for Flexible layouts; NULL if none)
* - $display->css_id (the special css_id that has been assigned to this display, if any; NULL if none)
* - $display->content (an array of pane objects, keyed by pane id (pid))
* - $display->panels (an associative array of panel regions, each an indexed array of pids in the order they appear in that region)
* - $display->cache (any relevant data from panels_simple_cache)
* - $display->args
* - $display->incoming_content
*
* While all of these members are defined, $display->context is NEVER defined in the returned $display;
* it must be set using one of the panels_context_create() functions.
*/
function panels_load_display($did) {
$displays = panels_load_displays(array(
$did,
));
if (!empty($displays)) {
return array_shift($displays);
}
}
/**
* Save a display object.
*
* @ingroup mainapi
*
* Note a new $display only receives a real did once it is run through this function.
* Until then, it uses a string placeholder, 'new', in place of a real did. The same
* applies to all new panes (whether on a new $display or not); in addition,
* panes have sequential numbers appended, of the form 'new-1', 'new-2', etc.
*
* @param object $display instanceof panels_display \n
* The display object to be saved. Passed by reference so the caller need not use
* the return value for any reason except convenience.
*
* @return object $display instanceof panels_display \n
*/
function panels_save_display(&$display) {
// @todo -- update all this to just use drupal_write_record or something like it.
if (!empty($display->did) && $display->did != 'new') {
db_query("UPDATE {panels_display} SET layout = '%s', layout_settings = '%s', panel_settings = '%s', cache = '%s', title = '%s', hide_title = %d WHERE did = %d", $display->layout, serialize($display->layout_settings), serialize($display->panel_settings), serialize($display->cache), $display->title, $display->hide_title, $display->did);
// Get a list of all panes currently in the database for this display so we can know if there
// are panes that need to be deleted. (i.e, aren't currently in our list of panes).
$result = db_query("SELECT pid FROM {panels_pane} WHERE did = %d", $display->did);
while ($pane = db_fetch_object($result)) {
$pids[$pane->pid] = $pane->pid;
}
}
else {
db_query("INSERT INTO {panels_display} (layout, layout_settings, panel_settings, cache, title, hide_title) VALUES ('%s', '%s', '%s', '%s', '%s', %d)", $display->layout, serialize($display->layout_settings), serialize($display->panel_settings), serialize($display->cache), $display->title, $display->hide_title);
$display->did = db_last_insert_id('panels_display', 'did');
$pids = array();
}
// update all the panes
panels_load_include('plugins');
foreach ((array) $display->panels as $id => $panes) {
$position = 0;
$new_panes = array();
foreach ((array) $panes as $pid) {
$pane = $display->content[$pid];
$pane->position = $position++;
// make variables right.
$type = panels_get_content_type($pane->type);
$access = isset($pane->access) ? implode(', ', $pane->access) : '';
$visibility = !empty($type['visibility serialize']) ? serialize($pane->visibility) : $pane->visibility;
$pane->shown = isset($pane->shown) ? $pane->shown : TRUE;
if (empty($pane->cache)) {
$pane->cache = array();
}
$v = array(
$display->did,
$pane->panel,
$pane->type,
$pane->subtype,
serialize($pane->configuration),
serialize($pane->cache),
$pane->shown,
$access,
$visibility,
$pane->position,
);
if (!is_numeric($pid)) {
unset($display->content[$pid]);
// doin it this way for readability
$f = 'did, panel, type, subtype, configuration, cache, shown, access, visibility, position';
$q = "%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d";
db_query("INSERT INTO {panels_pane} ({$f}) VALUES ({$q})", $v);
$pane->pid = db_last_insert_id('panels_pane', 'pid');
}
else {
$v[] = $pane->pid;
$f = "did = %d, panel = '%s', type = '%s', subtype = '%s', configuration = '%s', cache = '%s', shown = '%s', access = '%s', visibility = '%s', position = '%d'";
db_query("UPDATE {panels_pane} SET {$f} WHERE pid = %d", $v);
}
// and put it back so our pids and positions can be used
$display->content[$pane->pid] = $pane;
$new_panes[] = $pane->pid;
if (isset($pids[$pane->pid])) {
unset($pids[$pane->pid]);
}
}
$display->panels[$id] = $new_panes;
}
if (!empty($pids)) {
db_query("DELETE FROM {panels_pane} WHERE pid IN (" . db_placeholders($pids) . ")", $pids);
}
// Clear any cached content for this display.
panels_clear_cached_content($display);
// to be nice, even tho we have a reference.
return $display;
}
/**
* Delete a display.
*/
function panels_delete_display($display) {
if (is_object($display)) {
$did = $display->did;
}
else {
$did = $display;
}
db_query("DELETE FROM {panels_display} WHERE did = %d", $did);
db_query("DELETE FROM {panels_pane} WHERE did = %d", $did);
}
/**
* Exports the provided display into portable code.
*
* This function is primarily intended as a mechanism for cloning displays.
* It generates an exact replica (in code) of the provided $display, with
* the exception that it replaces all ids (dids and pids) with 'new-*' values.
* Only once panels_save_display() is called on the code version of $display will
* the exported display written to the database and permanently saved.
*
* @see panels_page_export() or _panels_page_fetch_display() for sample implementations.
*
* @ingroup mainapi
*
* @param object $display instanceof panels_display \n
* This export function does no loading of additional data about the provided
* display. Consequently, the caller should make sure that all the desired data
* has been loaded into the $display before calling this function.
* @param string $prefix
* A string prefix that is prepended to each line of exported code. This is primarily
* used for prepending a double space when exporting so that the code indents and lines up nicely.
*
* @return string $output
* The passed-in $display expressed as code, ready to be imported. Import by running
* eval($output) in the caller function; doing so will create a new $display variable
* with all the exported values. Note that if you have already defined a $display variable in
* the same scope as where you eval(), your existing $display variable WILL be overwritten.
*/
function panels_export_display($display, $prefix = '') {
$output = '';
$output .= $prefix . '$display = new panels_display()' . ";\n";
$output .= $prefix . '$display->did = \'new\'' . ";\n";
// $fields = array('name', 'layout', 'layout_settings', 'panel_settings');
// TODO 'name' field was removed several months ago, so temporarily removing
// it from here whil investigations into exactly why it was removed continue
$fields = array(
'layout',
'layout_settings',
'panel_settings',
);
foreach ($fields as $field) {
$output .= $prefix . '$display->' . $field . ' = ' . panels_var_export($display->{$field}, $prefix) . ";\n";
}
$output .= $prefix . '$display->content = array()' . ";\n";
$output .= $prefix . '$display->panels = array()' . ";\n";
$panels = array();
if (!empty($display->content)) {
$pid_counter = 0;
$region_counters = array();
foreach ($display->content as $pane) {
$pane->pid = 'new-' . ++$pid_counter;
$output .= panels_export_pane($pane, $prefix . ' ');
$output .= "{$prefix} " . '$display->content[\'' . $pane->pid . '\'] = $pane' . ";\n";
if (!isset($region_counters[$pane->panel])) {
$region_counters[$pane->panel] = 0;
}
$output .= "{$prefix} " . '$display->panels[\'' . $pane->panel . '\'][' . $region_counters[$pane->panel]++ . '] = \'' . $pane->pid . "';\n";
}
}
return $output;
}
function panels_export_pane($pane, $prefix = '') {
$output = '';
$output = $prefix . '$pane = new stdClass()' . ";\n";
$fields = array(
'pid',
'panel',
'type',
'shown',
'subtype',
'access',
'configuration',
'cache',
);
foreach ($fields as $field) {
$output .= "{$prefix} " . '$pane->' . $field . ' = ' . panels_var_export($pane->{$field}, "{$prefix} ") . ";\n";
}
return $output;
}
function panels_var_export($object, $prefix = '') {
if (is_array($object) && empty($object)) {
$output = 'array()';
}
else {
// Remove extra space to match Drupal coding standards.
$output = str_replace('array (', 'array(', var_export($object, TRUE));
}
if ($prefix) {
$output = str_replace("\n", "\n{$prefix}", $output);
}
return $output;
}
/**
* Render a display by loading the content into an appropriate
* array and then passing through to panels_render_layout.
*
* if $incoming_content is NULL, default content will be applied. Use
* an empty string to indicate no content.
* @render
* @ingroup hook_invocations
*/
function panels_render_display(&$display) {
panels_load_include('display-render');
panels_load_include('plugins');
return _panels_render_display($display);
}
/**
* For external use: Given a layout ID and a $content array, return the
* panel display. The content array is filled in based upon the content
* available in the layout. If it's a two column with a content
* array defined like array('left' => t('Left side'), 'right' =>
* t('Right side')), then the $content array should be array('left' =>
* $output_left, 'right' => $output_right)
* @render
*/
function panels_print_layout($id, $content) {
panels_load_include('plugins');
return _panels_print_layout($id, $content);
}
// @layout
function panels_print_layout_icon($id, $layout, $title = NULL) {
drupal_add_css(panels_get_path('css/panels_admin.css'));
$file = $layout['path'] . '/' . $layout['icon'];
return theme('panels_layout_icon', $id, theme('image', $file), $title);
}
/**
* Theme the layout icon image
* @layout
* @todo move to theme.inc
*/
function theme_panels_layout_icon($id, $image, $title = NULL) {
$output = '<div class="layout-icon">';
$output .= $image;
if ($title) {
$output .= '<div class="caption">' . $title . '</div>';
}
$output .= '</div>';
return $output;
}
/**
* Theme the layout link image
* @layout
*/
function theme_panels_layout_link($title, $id, $image, $link) {
$output = '<div class="layout-link">';
$output .= $image;
$output .= '<div>' . $title . '</div>';
$output .= '</div>';
return $output;
}
/**
* Print the layout link. Sends out to a theme function.
* @layout
*/
function panels_print_layout_link($id, $layout, $link) {
drupal_add_css(panels_get_path('css/panels_admin.css'));
$file = $layout['path'] . '/' . $layout['icon'];
$image = l(theme('image', $file), $link, array(
'html' => true,
));
$title = l($layout['title'], $link);
return theme('panels_layout_link', $title, $id, $image, $link);
}
/**
* Implementation of hook_ctools_plugin_directory() to let the system know
* we implement task and task_handler plugins.
*/
function panels_ctools_plugin_directory($plugin) {
if ($plugin == 'tasks' || $plugin == 'task_handlers') {
return 'plugins/' . $plugin;
}
}
Functions
Name![]() |
Description |
---|---|
panels_api_version | Returns the API version of Panels. This didn't exist in 1. |
panels_cache_clear | Clear a object from the cache; used if the editing is aborted. |
panels_cache_get | Get an object from cache. |
panels_cache_set | Save the edited object into the cache. |
panels_cron | Implementation of hook_cron. Clean up old caches. |
panels_ctools_plugin_directory | Implementation of hook_ctools_plugin_directory() to let the system know we implement task and task_handler plugins. |
panels_delete_display | Delete a display. |
panels_edit | Main API entry point to edit a panel display. |
panels_edit_layout | API entry point for selecting a layout for a given display. |
panels_edit_layout_settings | API entry point for configuring the layout settings for a given display. |
panels_export_display | Exports the provided display into portable code. |
panels_export_pane | |
panels_export_pane_across_displays | }@ End of 'defgroup mainapi', although other functions are specifically added later |
panels_get_path | panels path helper function |
panels_init | Implementation of hook_init() |
panels_load_display | Load a single display. |
panels_load_displays | Load and fill the requested $display object(s). |
panels_load_include | Load a panels include file. |
panels_menu | Implementation of hook_menu |
panels_new_display | Creates a new display, setting the ID to our magic new id. |
panels_new_pane | |
panels_perm | Implementation of hook_perm |
panels_print_layout | For external use: Given a layout ID and a $content array, return the panel display. The content array is filled in based upon the content available in the layout. If it's a two column with a content array defined like array('left' =>… |
panels_print_layout_icon | |
panels_print_layout_link | Print the layout link. Sends out to a theme function. @layout |
panels_render_display | Render a display by loading the content into an appropriate array and then passing through to panels_render_layout. |
panels_sanitize_display | Clean up a display object and add some required information, if missing. |
panels_save_display | Save a display object. |
panels_theme | |
panels_var_export | |
theme_panels_layout_icon | Theme the layout icon image @layout @todo move to theme.inc |
theme_panels_layout_link | Theme the layout link image @layout |
Constants
Name![]() |
Description |
---|---|
PANELS_ARG_IS_BAD | Error code bitmask used for identifying argument behavior at runtime. |
PANELS_ARG_USE_FALLBACK |
Classes
Name![]() |
Description |
---|---|
panels_display | Forms the basis of a panel display |