' . t('Grab the title bar of any pane to drag it to another panel. Click the add pane button in any panel to add more content. Click the configure button on any pane to re-configure that pane.') . '
',
);
$old_layout_panels = panels_get_panels($old_layout, $display);
foreach ($display->panels as $id => $content) {
$form['old'][$id] = array(
'#type' => 'select',
'#title' => t('Move content in @layout to', array('@layout' => $old_layout_panels[$id])),
'#options' => $options,
'#default_value' => array_key_exists($id, $options) ? $id : $default,
);
}
$form['back'] = array(
'#type' => 'submit',
'#value' => t('Back'),
);
return $form;
}
/**
* Shortcut to the panels layout settings editor
*
* TODO: Doc this. Important.
*/
function panels_edit_layout_settings($display, $finish, $destination) {
return drupal_get_form('panels_edit_layout_settings_form', $display, $finish, $destination);
}
/**
* Form to change the layout of a display.
*/
function panels_edit_layout_settings_form($display, $finish, $destination) {
$layout = panels_get_layout($display->layout);
if (!empty($layout['settings form']) && function_exists($layout['settings form'])) {
$form['layout_settings'] = $layout['settings form']($display, $layout, $display->layout_settings);
}
$form['layout_settings']['#tree'] = TRUE;
$form['variables'] = array(
'#type' => 'value',
'#value' => array($display, $finish, $destination),
);
$form['layout'] = array(
'#type' => 'value',
'#value' => $layout,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => $finish,
);
return $form;
}
function panels_edit_layout_settings_form_validate($form_id, $form_values, $form) {
list($display, $finish, $destination) = $form_values['variables'];
$layout = $form_values['layout'];
if (!empty($layout['settings validate']) && function_exists($layout['settings validate'])) {
$layout['settings validate']($form_values['layout_settings'], $form['layout_settings'], $display, $layout, $display->layout_settings);
}
}
function panels_edit_layout_settings_form_submit($form_id, $form_values) {
list($display, $finish, $destination) = $form_values['variables'];
$layout = $form_values['layout'];
if (!empty($layout['settings submit']) && function_exists($layout['settings submit'])) {
$layout['settings submit']($form_values['layout_settings'], $display, $layout, $display->layout_settings);
}
if ($form_values['op'] == $finish) {
$display->layout_settings = $form_values['layout_settings'];
panels_save_display($display);
drupal_set_message("Your layout settings have been saved.");
return $destination;
}
}
/**
* @defgroup panels_content Panels content and pane helper/info functions
* @{
*/
/**
* Determine visibility of a panel pane
*
* @param $pane
* The pane object to test.
* @param $account
* The account to test access against.
*/
function panels_pane_access($pane, $account = NULL) {
if (!$account) {
global $user;
$account = $user;
}
// Administrator privileges
if (user_access('view all pane', $account)) {
return TRUE;
}
// All views with an empty access setting are available to all roles.
if (!$pane->access || !is_array($pane->access)) {
return TRUE;
}
// Otherwise, check roles
static $roles = array();
if (!isset($roles[$account->uid])) {
$roles[$account->uid] = array_keys($account->roles);
$roles[$account->uid][] = $account->uid ? DRUPAL_AUTHENTICATED_RID : DRUPAL_ANONYMOUS_RID;
}
return array_intersect($pane->access, $roles[$account->uid]);
}
/**
* Get the function to call for a given operation on a content type.
*
* @param $type
* The content type to check. May be the name (which loads the content type) or
* an already loaded content type object.
* @param $name
* The name of the function to retrieve; this will be set in the content type
* definition. May be:
* - render callback
* - title callback
* - add callback
* - add validate callback
* - add submit callback
* - edit callback
* - edit validate callback
* - edit submit callback
*/
function panels_ct_function($type, $name) {
if (is_object($type)) {
$content_type = $type;
}
else {
$content_type = panels_get_content_type($type);
}
$function = $content_type[$name];
if (function_exists($function)) {
return $function;
}
}
/**
* Get the content from a given content type.
*
* @param $type
* The content type. May be the name or an already loaded content type object.
* @param $conf
* The configuration for the content type.
* @param $args
* The arguments to the content type.
* @param $context
* The panels_context object.
* @Param $incoming_content
* Any incoming content, if this display is a wrapper.
*/
function panels_ct_get_content($type, $conf, $args, $context, $incoming_content) {
if ($function = panels_ct_function($type, 'render callback')) {
return $function($conf, $args, $context, $incoming_content);
}
}
/**
* Get the title from a given content type.
*
* @param $type
* The content type. May be the name or an already loaded content type object.
* @param $conf
* The configuration for the content type.
*/
function panels_ct_get_title($type, $conf) {
if ($function = panels_ct_function($type, 'title callback')) {
return $function($conf);
}
}
/**
* Get the form to add a new instance of a content type.
*
* @param $type
* The content type. May be the name or an already loaded content type object.
* @param $id
* The identifier for the content to add; this is specific to the type of
* content.
* @param $parents
* The #parents to be used on the form, because some form gadgets need to
* know where they live.
*/
function panels_ct_get_add_form($type, $id, $parents) {
if ($function = panels_ct_function($type, 'add callback')) {
return $function($id, $parents);
}
}
/**
* Call the validate handler for the add form for a content type.
* @param $type
* The content type. May be the name or an already loaded content type object.
* @param $form
* The actual Forms API form that is being validated.
* @param $form_values
* The actual Forms API values being validated.
*/
function panels_ct_validate_add_form($type, $form, $form_values) {
if ($function = panels_ct_function($type, 'add validate callback')) {
return $function($form, $form_values);
}
}
/**
* Call the submit handler for the add form for a content type.
* @param $type
* The content type. May be the name or an already loaded content type object.
* @param $form_values
* The actual Forms API values being validated.
*/
function panels_ct_submit_add_form($type, $form_values) {
if ($function = panels_ct_function($type, 'add submit callback')) {
return $function($form_values);
}
}
/**
* Get the form to edit an instance of a content type.
*
* @param $type
* The content type. May be the name or an already loaded content type object.
* @param $id
* The identifier for the content to add; this is specific to the type of
* content.
* @param $parents
* The #parents to be used on the form, because some form gadgets need to
* know where they live.
*/
function panels_ct_get_edit_form($type, $conf, $parents) {
if ($function = panels_ct_function($type, 'edit callback')) {
return $function($conf, $parents);
}
}
/**
* Call the validate handler for the edit form for a content type.
* @param $type
* The content type. May be the name or an already loaded content type object.
* @param $form
* The actual Forms API form that is being validated.
* @param $form_values
* The actual Forms API values being validated.
*/
function panels_ct_validate_edit_form($type, $form, $form_values) {
if ($function = panels_ct_function($type, 'edit validate callback')) {
return $function($form, $form_values);
}
}
/**
* Call the submit handler for the edit form for a content type.
* @param $type
* The content type. May be the name or an already loaded content type object.
* @param $form_values
* The actual Forms API values being validated.
*/
function panels_ct_submit_edit_form($type, $form_values) {
if ($function = panels_ct_function($type, 'edit submit callback')) {
return $function($form_values);
}
}
/**
* Get all of the individual types provided by a given content types. This
* would be all of the blocks for the block type, or all of the views for
* the view type.
*
* @param $type
* The content type to load.
*/
function panels_ct_get_types($type) {
if (is_array($type)) {
$content_type = $type;
}
else {
$content_type = panels_get_content_type($type);
}
$function = $content_type['content_types'];
if (is_array($function)) {
return $function;
}
if (function_exists($function)) {
return $function($conf);
}
}
/**
* Get an array of all available content types that can be fed into the
* display editor for the add content list.
*
* @param $context
* If a context is provided, content that requires that context can apepar.
* @param $
*/
function panels_get_available_content_types($context = NULL, $has_content = FALSE) {
$content_types = panels_get_content_types();
$available = array();
foreach ($content_types as $id => $type) {
// exclude items that require content if we're saying we don't
// provide it.
if (!empty($type['requires content']) && !$has_content) {
continue;
}
// Check to see if the content type can be used in this context.
if (!isset($type['required context']) ||
(is_array($type['required_context']) &&
in_array($context, $type['required_context'])) ||
($type['required_context'] == $context)) {
$available[$id] = panels_ct_get_types($type);
}
}
return $available;
}
function panels_get_panels($layout, $display) {
if (!empty($layout['panels function']) && function_exists($layout['panels function'])) {
return $layout['panels function']($display, $display->layout_settings);
}
if (!empty($layout['panels'])) {
return $layout['panels'];
}
return array();
}
// ------------------------------------------------------------------
// Functions to provide information about a panel or part of a panel.
/**
* Get the content from a given pane.
*
* @param $pane
* The pane to retrieve content from.
* @param $args
* The arguments sent to the display.
* @param $context
* The panels context.
* @param $incoming_content
* Any incoming content if this display is a wrapper.
*/
function panels_get_pane_content($pane, $args = array(), $context = NULL, $incoming_content = '') {
if (!$context) {
$context = new panels_context;
}
if (!$incoming_content === '') {
$incoming_content = t('Incoming content will be displayed here.');
}
return panels_ct_get_content($pane->type, $pane->configuration, $args, $context, $incoming_content);
}
/**
* Get the title of a pane.
*
* @param $pane
* The $pane object.
*/
function panels_get_pane_title($pane) {
return panels_ct_get_title($pane->type, $pane->configuration);
}
/**
* Display the edit form for a pane.
*
* @param $pane
* The pane to edit.
* @param $parents
* The form api #parents array for that this subform will live in.
*/
function panels_get_pane_edit_form($pane, $parents) {
return panels_ct_get_edit_form($pane->type, $pane->configuration, $parents);
}
/**
* Render a single pane in the edit environment.
*
* @param $pane
* The pane to render.
* @param $left_buttons
* Buttons that go on the left side of the pane.
* @param $buttons
* Buttons that go on the right side of
* @param $skin
* If true, provide the outside div. Used to provide an easy way to get
* just the innards for ajax replacement
*/
function panels_show_pane($pane, $left_buttons, $buttons, $skin = TRUE) {
$block = panels_get_pane_content($pane);
$title = panels_get_pane_title($pane);
$output = theme('panels_pane_dnd', $block, $pane->pid, $title, $left_buttons, $buttons);
if ($skin) {
$output = '
' . $output . '
';
}
return $output;
}
/**
* @} End of "defgroup panels_content".
*/
/**
* @defgroup panels_ajax Functions for panels ajax features
* @{
*/
/**
* Simple render function to make sure output is what we want.
*/
function panels_ajax_render($output = NULL, $title = NULL) {
if (!is_object($output)) {
$temp = new stdClass();
$temp->output = $output;
$temp->type = 'display';
$temp->title = $title;
$output = $temp;
}
if (!$output->output || !$output->type) {
$output->output = t('The input was invalid');
$output->type = 'display';
$output->title = t('Error');
}
drupal_set_header('Content-Type: text/javascript; charset=utf-8');
print drupal_to_js($output);
exit;
}
/**
* entry point into all the ajax stuff
*/
function panels_ajax($op = NULL, $did = NULL, $pid = NULL) {
switch ($op) {
case 'submit-form':
if ((is_numeric($did) || $did == 'new') && $cache = panels_cache_get($did)) {
$output = panels_edit_submit_subform($cache->display);
}
break;
}
panels_ajax_render($output);
}
function panels_ajax_add_content($did = NULL, $panel_id = NULL) {
if ((is_numeric($did) || $did == 'new') && $cache = panels_cache_get($did)) {
$display = $cache->display;
$layout = panels_get_layout($display->layout);
$layout_panels = panels_get_panels($layout, $display);
if ($layout && array_key_exists($panel_id, $layout_panels)) {
$output->output = panels_add_content($cache, $panel_id);
$output->type = 'display';
$output->title = t('Add content to !s', array('!s' => $layout_panels[$panel_id]));
}
}
panels_ajax_render($output);
}
function panels_add_content($cache, $panel_id) {
$return->type = 'display';
$return->title = t('Choose type');
panels_set('return', $return);
if (!isset($cache->content_types)) {
$cache->content_types = panels_get_available_content_types();
}
$weights = array(t('Contributed modules') => 0);
$categories = array();
$titles = array();
foreach ($cache->content_types as $id => $types) {
if (is_array($types)) {
foreach ($types as $content_id => $info) {
if (isset($info['icon'])) {
$icon = $info['icon'];
if (isset($info['path'])) {
$path = $info['path'];
}
else {
$path = panels_get_path("content_types/$id");
}
}
else {
$icon = 'no-icon.png';
$path = panels_get_path('images');
}
$title = filter_xss_admin($info['title']);
if (isset($info['description'])) {
$description = $info['description'];
}
else {
$description = $title;
}
if (isset($info['category'])) {
if (is_array($info['category'])) {
list($category, $weight) = $info['category'];
$weights[$category] = $weight;
}
else {
$category = $info['category'];
if (!isset($weights['category'])) {
$weights[$category] = 0;
}
}
}
else {
$category = t('Contrib modules');
}
$output = '
');
$form['did'] = array(
'#type' => 'value',
'#value' => $display->did,
);
$form['type'] = array(
'#type' => 'value',
'#value' => $content_type_id,
);
$form['panel'] = array(
'#type' => 'value',
'#value' => $panel_id,
);
$form['configuration'] = $conf;
$form['configuration']['#tree'] = TRUE;
if (user_access('administer pane visibility')) {
$rids = array();
$result = db_query("SELECT r.rid, r.name FROM {role} r ORDER BY r.name");
while ($obj = db_fetch_object($result)) {
$rids[$obj->rid] = $obj->name;
}
$form['access'] = array(
'#type' => 'checkboxes',
'#title' => t('Access'),
'#default_value' => array(),
'#options' => $rids,
'#description' => t('Only the checked roles will be able to see this pane; if no roles are checked, access will not be restricted.'),
);
}
else {
$form['access'] = array(
'#type' => 'value',
'#value' => array(),
);
}
$form['end_form'] = array('#value' => '
');
$form['next'] = array(
'#type' => 'submit',
'#value' => t('Add pane'),
);
$return->type = 'display';
$return->title = t('Configure !s', array('!s' => $title));
panels_set('return', $return);
return $form;
}
function panels_add_content_config_form_validate($form_id, $form_values, $form) {
panels_ct_validate_add_form($form_values['type'], $form['configuration'], $form_values['configuration']);
}
function panels_add_content_config_form_submit($form_id, $form) {
$cache = panels_cache_get($form['did']);
// keep an incrementing counter, add the data to the display.
// This counter is so that we can add this pane to the cache but not
// make it real until the final 'Save' is clicked.
$pid = ++$cache->highest;
$form['pid'] = "new-$pid";
$form['access'] = array_keys(array_filter($form['access']));
panels_ct_submit_add_form($form['type'], $form['configuration']);
$cache->display->content[$form['pid']] = (object) $form;
$cache->display->panels[$form['panel']][] = $form['pid'];
// drupal_set_message('
' . var_export($cache->display, true) . '
');
panels_cache_set($form['did'], $cache);
// Set info for the javascript so it knows where to put the new pane.
// FIXME: Note that ->area appears to be a holdover -- it should be ->panel now.
$return->type = 'add';
$return->area = $form['panel'];
$return->id = $form['pid'];
// we need to fake the buttons a little.
$buttons['configure'] = panels_add_button('configure.gif', t('Configure'), t('Configure this pane'), 'pane-configure');
$buttons['configure']['#parents'] = array('button', $form['pid'], 'configure');
$buttons['delete'] = panels_add_button('close.gif', t('Delete'), t('Remove this pane'), 'pane-delete');
$buttons['delete']['#parents'] = array('button', $form['pid'], 'delete');
$buttons = form_builder('dummy', $buttons);
// Render the new pane for the javascript.
$return->output = panels_show_pane($cache->display->content[$form['pid']], NULL, drupal_render($buttons));
panels_set('return', $return);
return FALSE;
}
function panels_ajax_configure($did = NULL, $pid = NULL) {
if ((is_numeric($did) || $did == 'new') && $cache = panels_cache_get($did)) {
$text = drupal_get_form('panels_edit_pane_config_form', $cache->display, $pid);
$output = panels_get('return');
$output->output = $text;
}
panels_ajax_render($output);
}
function panels_edit_pane_config_form($display, $pid = NULL) {
$cache = panels_cache_get($display->did);
if ($pid === NULL) {
if (isset($cache->pid)) {
$pid = $cache->pid;
}
else {
return array();
}
}
else {
$cache->pid = $pid;
panels_cache_set($display->did, $cache);
}
$pane = $display->content[$pid];
$form['start_form'] = array('#value' => '
');
$form['did'] = array(
'#type' => 'value',
'#value' => $display->did,
);
$form['pid'] = array(
'#type' => 'value',
'#value' => $pid,
);
$form['type'] = array(
'#type' => 'value',
'#value' => $content_type_id,
);
$return->title = t('Configure !s', array('!s' => panels_get_pane_title($pane)));
$form['configuration'] = panels_get_pane_edit_form($pane, array('configuration'));
$form['configuration']['#tree'] = true;
if (user_access('administer pane visibility')) {
$rids = array();
$result = db_query("SELECT r.rid, r.name FROM {role} r ORDER BY r.name");
while ($obj = db_fetch_object($result)) {
$rids[$obj->rid] = $obj->name;
}
$form['access'] = array(
'#type' => 'checkboxes',
'#title' => t('Access'),
'#default_value' => $pane->access,
'#options' => $rids,
'#description' => t('Only the checked roles will be able to see this pane; if no roles are checked, access will not be restricted.'),
);
}
else {
$form['access'] = array(
'#type' => 'value',
'#value' => $pane->access,
);
}
$return->type = 'display';
panels_set('return', $return);
$form['end_form'] = array('#value' => '
');
$form['next'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
return $form;
}
function panels_edit_pane_config_form_validate($form_id, $form_values, $form) {
panels_ct_validate_edit_form($form_values['type'], $form['configuration'], $form_values['configuration']);
}
function panels_edit_pane_config_form_submit($form_id, $form) {
// save the new configuration.
$cache = panels_cache_get($form['did']);
panels_ct_submit_edit_form($form['type'], $form['configuration']);
$cache->display->content[$form['pid']]->access = array_keys(array_filter($form['access']));
$cache->display->content[$form['pid']]->configuration = $form['configuration'];
panels_cache_set($form['did'], $cache);
$return->type = 'replace';
$return->id = $form['pid'];
$block = panels_get_pane_content($cache->display->content[$form['pid']]);
if (!$block->subject) {
$block->subject = t('No title');
}
$return->output = theme('panels_pane_collapsible', $block, $cache->display);
panels_set('return', $return);
return FALSE;
}
function panels_edit_submit_subform($display) {
// Check forms to make sure only valid forms can be rendered this way.
$valid_forms = array('panels_add_content_config_form', 'panels_edit_pane_config_form');
$form_id = $_POST['form_id'];
if (!in_array($form_id, $valid_forms)) {
return panels_ajax_render();
}
$output = drupal_get_form($form_id, $display);
$next = panels_get('next');
if ($next) {
$output = drupal_get_form($next['form'], $display, $next['data']);
$return = panels_get('return');
if (!$return->output) {
$return->output = $output;
}
}
else {
if (!($return = panels_get('return'))) {
$return->type = 'display';
$return->output = $output;
}
else if ($return->type == 'display' && !$return->output) {
$return->output = $output;
}
}
if ($return->type == 'display') {
$return->output = theme('status_messages') . $return->output;
}
return $return;
}
/**
* @} End of "defgroup panels_content".
*/
// ---------------------------------------------------------------------------
// panels database functions
/**
* Forms the basis of a panel display and provides a constructur to ensure
* that the display always has a valid context.
*/
class panels_display {
var $args = array();
var $incoming_content = NULL;
var $context = NULL;
var $css_id = NULL;
function panels_display($context = NULL) {
if (!isset($context)) {
$this->context = new panels_context();
}
}
}
/**
* Creates a new display with the given context, so that users don't
* have to mess with classes if they don't want to.
*/
function panels_new_display($context = NULL) {
$display = new panels_display($context);
$display->did = 'new';
return $display;
}
/**
* Load a display from the database and set a context.
*/
function panels_load_displays($dids, $context = NULL) {
$displays = array();
if (empty($dids) || !is_array($dids)) {
return $displays;
}
$subs = implode(', ', array_fill(0, count($dids), '%d'));
$result = db_query("SELECT * FROM {panels_display} WHERE did IN ($subs)", $dids);
while ($obj = db_fetch_array($result)) {
$display = new panels_display($context);
foreach ($obj as $key => $value) {
$display->$key = $value;
}
// unserialize important bits:
if (!empty($display->layout_settings)) {
$display->layout_settings = unserialize($display->layout_settings);
}
else {
$display->layout_settings = array();
}
if (!empty($display->panel_settings)) {
$display->panel_settings = unserialize($display->panel_settings);
}
else {
$display->panel_settings = array();
}
$display->panels = $display->content = array();
$displays[$display->did] = $display;
}
$result = db_query("SELECT * FROM {panels_pane} WHERE did IN ($subs) ORDER BY did, panel, position", $dids);
while ($pane = db_fetch_object($result)) {
$pane->configuration = unserialize($pane->configuration);
$pane->access = ($pane->access ? explode(', ', $pane->access) : array());
$displays[$pane->did]->panels[$pane->panel][] = $pane->pid;
$displays[$pane->did]->content[$pane->pid] = $pane;
}
return $displays;
}
/**
* Load a single display.
*/
function panels_load_display($did, $context = NULL) {
$displays = panels_load_displays(array($did), $context);
if (!empty($displays)) {
return array_shift($displays);
}
}
/**
* Save a display.
*/
function panels_save_display(&$display) {
if ($display->did && $display->did != 'new') {
db_query("UPDATE {panels_display} SET layout = '%s', layout_settings = '%s', panel_settings = '%s' WHERE did = %d", $display->layout, serialize($display->layout_settings), serialize($display->panel_settings), $display->did);
db_query("DELETE FROM {panels_pane} WHERE did = %d", $display->did);
}
else {
$display->did = db_next_id("{panels_display}_id");
db_query("INSERT INTO {panels_display} (did, layout, layout_settings, panel_settings) VALUES (%d, '%s', '%s', '%s')", $display->did, $display->layout, serialize($display->layout_settings), serialize($display->panel_settings));
}
// update all the panes
foreach ((array) $display->panels as $id => $panes) {
$position = 0;
$new_panes = array();
foreach ((array) $panes as $pid) {
$pane = $display->content[$pid];
$pane->position = $position++;
if (!is_numeric($pid)) {
unset($display->content[$pid]);
$pane->pid = db_next_id("{panels_pane}_pid");
}
db_query("INSERT INTO {panels_pane} (pid, did, panel, type, configuration, access, position) VALUES (%d, %d, '%s', '%s', '%s', '%s', %d)", $pane->pid, $display->did, $pane->panel, $pane->type, serialize($pane->configuration), !empty($pane->access) ? implode(', ', $pane->access) : '', $pane->position);
// and put it back so our pids and positions can be used
$display->content[$pid] = $pane;
$new_panes[] = $pid;
}
$display->panels[$id] = $panes;
}
return $display; // to be nice, even tho we have a reference.
}
/**
* Delete a display
*/
function panels_delete_display($display) {
db_query("DELETE FROM {panels_display} WHERE did = %d", $display->did);
db_query("DELETE FROM {panels_pane} WHERE did = %d", $display->did);
}
/**
* Export a display into code
*/
function panels_export_display($display) {
$output = '';
$output .= '$display = new stdClass()' . ";\n";
$output .= '$display->did = \'new\'' . ";\n";
$fields = array('name', 'layout', 'layout_settings', 'panel_settings');
foreach ($fields as $field) {
$output .= '$display->' . $field . ' = ' . var_export($display->$field, TRUE) . ";\n";
}
$output .= '$display->content = array()' . ";\n";
$output .= '$display->panels = array()' . ";\n";
$panels = array();
$counter = 0;
$counters = array();
foreach ($display->content as $pane) {
$id = 'new-' . ++$counter;
$output .= '$pane = new stdClass()' . ";\n";
$fields = array('panel', 'type', 'access', 'configuration');
foreach ($fields as $field) {
$output .= ' $pane->' . $field . ' = ' . var_export($pane->$field, TRUE) . ";\n";
}
$output .= '$display->content[\'' . $id . '\'] = $pane' . ";\n";
if (!isset($counters[$pane->panel])) {
$counters[$pane->panel] = 0;
}
$output .= '$display->panels[\'' . $pane->panel . '\'][' . $counters[$pane->panel]++ .'] = \'' . $id . "';\n";
}
return $output;
}
/**
* 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)
*/
function panels_print_layout($id, $content) {
$layout = panels_get_layout($id);
if (!$layout) {
return;
}
return panels_render_layout($layout, $content);
}
/**
* Given a full layout structure and a content array, render a panel display.
*/
function panels_render_layout($layout, $content, $css_id = NULL, $settings = array()) {
if (file_exists(path_to_theme() . '/' . $layout['css'])) {
drupal_add_css(path_to_theme() . '/' . $layout['css']);
}
else {
drupal_add_css(panels_get_path($layout['css'], false, $layout['module']));
}
// This now comes after the CSS is added, because panels-within-panels must
// have their CSS added in the right order; inner content before outer content.
if (is_object($content)) {
$display = $content;
$content = array();
// Loop through all panels, put all panes that belong to the current panel
// in an array, then render the panel.
foreach ($display->panels as $panel_name => $panes) {
$panes_in_panel = array_intersect_key($display->content, array_flip($panes));
$content[$panel_name] = panels_render_panel($panes_in_panel, $display);
}
}
$output = theme($layout['theme'], check_plain($css_id), $content, $settings);
return $output;
}
class panels_context {
var $type = NULL;
var $data = NULL;
function panels_context($type = 'none', $data = NULL) {
$this->type = $type;
$this->data = $data;
}
}
/**
* Clean up a display and make sure it has some required information if
* it doesn't already exist. Currently we wrequire a context, an incoming
* content and a css_id.
*/
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 = new panels_context();
}
if (!isset($display->css_id)) {
$display->css_id = NULL;
}
}
/**
* 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.
*/
function panels_render_display(&$display) {
$layout = panels_get_layout($display->layout);
if (!$layout) {
return NULL;
}
panels_sanitize_display($display);
return panels_render_layout($layout, $display, $display->css_id, $display->layout_settings);
}
/**
* Render a panel, by storing the content of each pane in an appropriate array
* and then passing through to the theme function that will render the panel
* in the configured panel style.
*
* @param $panes
* An array of panes that are assigned to the panel that's being rendered.
* @param $display
* A display object.
* @return
* The rendered HTML for a panel.
*/
function panels_render_panel($panes_in_panel, $display) {
if (!empty($display->panel_settings)) {
$style = panels_get_panel_style($display->panel_settings['style']);
}
else {
$style = array('name' => 'default', 'module' => 'panels');
};
// Store all panes in an array, sorted by their position in the panel.
$panes = array();
foreach ($panes_in_panel as $pane_id => $pane) {
if (panels_pane_access($pane)) {
$panes[$pane->position] = panels_get_pane_content($pane, $display->args, $display->context, $display->incoming_content);
}
}
// 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.
$pid = 0;
if (isset($display->owner) && is_object($display->owner) && isset($display->owner->pid)) {
$panel_id = $display->owner->pid;
}
return module_invoke($style['module'], 'panels_panel_style_render', $display, $style['name'], $panel_id, $panes);
}
// ---------------------------------------------------------------------------
// panels data loading
function panels_load_includes($directory, $callback, $file = NULL) {
// Load all our module 'on behalfs'.
$path = panels_get_path($directory);
$files = drupal_system_listing("$file" . '.inc$', $path, 'name', 0);
foreach($files as $file) {
require_once('./' . $file->filename);
}
$output = module_invoke_all($callback);
foreach ($files as $file) {
$function = 'panels_' . $file->name . '_' . $callback;
if (function_exists($function)) {
$result = $function();
if (isset($result) && is_array($result)) {
$output = array_merge($output, $result);
}
}
}
return $output;
}
function panels_get_layout($layout) {
return panels_get_layouts($layout);
}
function panels_get_layouts($layout = NULL) {
static $layouts = array();
static $all_layouts = FALSE;
if (!$all_layouts) {
if (!$layout) {
$layouts = panels_load_includes('layouts', 'panels_layouts');
$all_layouts = TRUE;
}
else if (!array_key_exists($layout, $layouts)) {
$temp_layouts = panels_load_includes('layouts', 'panels_layouts', $layout);
if (isset($temp_layouts[$layout])) {
$layouts[$layout] = $temp_layouts[$layout];
}
}
}
if ($layout) {
return isset($layouts[$layout]) ? $layouts[$layout] : NULL;
}
return $layouts;
}
/**
* Collate information about a specific panel style.
*
* @param $style
* Name of a panel style.
* @return
* An array with information about the requested panel style.
*/
function panels_get_panel_style($style) {
return panels_get_panel_styles($style);
}
/**
* Collate information about all available panel styles.
*
* @param $style
* Name of a panel style.
* @return
* An array of arrays with information about all available panel styles. If
* the $style parameter specified an available panel style, only this array
* would be returned.
*/
function panels_get_panel_styles($style = NULL) {
static $styles;
if (!isset($styles)) {
foreach (module_list() as $module) {
$module_panel_styles = module_invoke($module, 'panels_panel_style_info');
if ($module_panel_styles) {
foreach ($module_panel_styles as $name => $panel_style_info) {
$styles[$name] = $panel_style_info;
$styles[$name]['name'] = $name;
$styles[$name]['module'] = $module;
}
}
}
}
if ($style) {
return isset($styles[$style]) ? $styles[$style] : NULL;
}
return $styles;
}
function panels_get_content_type($content_type) {
return panels_get_content_types($content_type);
}
function panels_get_content_types($content_type = NULL) {
static $content_types = array();
static $all_content_types = FALSE;
if (!$all_content_types) {
if (!$content_type) {
$content_types = panels_load_includes('content_types', 'panels_content_types');
$all_content_types = TRUE;
}
else if (!array_key_exists($content_type, $content_types)) {
$temp_content_types = panels_load_includes('content_types', 'panels_content_types', $content_type);
if (isset($temp_content_types[$content_type])) {
$content_types[$content_type] = $temp_content_types[$content_type];
}
}
}
if ($content_type) {
return isset($content_types[$content_type]) ? $content_types[$content_type] : NULL;
}
return $content_types;
}
/**
* Includes required JavaScript libraries:
* jQuery, iutil, idrag, idrop, isortables
* In addition to panels.js.
*/
function _panels_js_files() {
// while we don't use this directly some of our forms do.
drupal_add_js('misc/collapse.js');
drupal_add_js('misc/autocomplete.js');
drupal_add_js(panels_get_path('js/lib/dimensions.js'));
drupal_add_js(panels_get_path('js/lib/mc.js'));
drupal_add_js(panels_get_path('js/lib/form.js'));
drupal_add_js(array('panelsAjaxURL' => url('panels/ajax', NULL, NULL, TRUE)), 'setting');
drupal_add_js(panels_get_path('js/display_editor.js'));
drupal_add_css(panels_get_path('css/panels_dnd.css'));
drupal_add_css(panels_get_path('css/panels_admin.css'));
}
// ---------------------------------------------------------------------------
// Panels hooks
/**
* Implementation of hook_panels_panel_style_info().
*/
function panels_panels_panel_style_info() {
return array(
'default' => array(
'label' => t('Default'),
'panels implementations' => array(),
),
'list' => array(
'label' => t('List'),
'panels implementations' => array(),
),
);
}
/**
* Implementation of hook_panels_panel_style_render().
*/
function panels_panels_panel_style_render($display, $style, $panel_id, $panes) {
switch ($style) {
case 'default':
return theme('panels_panel_default', $display, $panel_id, $panes);
case 'list':
return theme('panels_panel_list', $display, $panel_id, $panes);
}
}
// ---------------------------------------------------------------------------
// Panels theming functions
function theme_panels_dnd($content) {
$output = "