'. t('Panels is the core engine for a number of submodules, including panels-pages, panels-nodes, and mini-panels. Panels allows the website adminstrator (or sometimes the end-user) to manipulate the layout of individual pages, sidebars, and content pieces, as well as easily dictate what content is displayed in the layout.') .'
'; $output .= ''. t('Most Drupal users are familiar with the block to region layout mechanism in which you can assign a block to any region defined in your theme. Panels takes this concept a massive step forward. Through the panels interface you can start by creating a layout with any number of columns, headers, and footer, and control the width of those areas.') .'
'; $output .= ''. t('After creating your layout, you can assign pieces of content to those areas in an easy drag and drop interface. Content is not limited to blocks, but can be nodes, views, blocks, or other types of content that extend themselves to panels.') .'
'; $output .= ''. t('Panels-pages') .'' .t(', is the the primary panels module, you can use this for creating single full page layouts. This replaces the standard panel that existed in the earlier versions of panels.') .'
'; $output .= ''. t('Panels-nodes') .'' .t(', is useful for creating layouts that only occupy the content area of your pages. Frequently, it is desirable to add an area to a node layout, such as a pull quote for a newspaper or a photo block, that you don\'t necessarily want on every node. Panels Nodes lets you control the layout of a single node at a time and place content such as blog posts, images, blogs in and around the post.') .'
'; $output .= ''. t('Mini-panels') .'' .t(', is a layout mechanism for blocks. It won\'t take long using panels before you get to a point when you want a panel inside of a panel. Or a panel that can be used as a block. That is exactly what mini-panels does. You can create a small panel here with various pieces of content and then put it inside of a panels-page or panels-node.') .'
'; return $output; } } /** * 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); } /** * Implementation of hook_menu */ function panels_menu($may_cache) { if ($may_cache) { $items[] = array( 'path' => 'admin/panels', 'title' => t('Panels'), 'access' => user_access('access administration pages'), 'callback' => 'system_admin_menu_block_page', 'description' => t('Administer items related to the Panels module.'), ); $items[] = array( 'path' => 'panels/node/autocomplete', 'title' => t('Autocomplete node'), 'callback' => 'panels_node_autocomplete', 'access' => user_access('access content'), 'type' => MENU_CALLBACK ); $items[] = array( 'path' => 'panels/ajax', 'title' => t('ajax'), 'callback' => 'panels_ajax_passthru', 'callback arguments' => array('panels_ajax'), 'access' => user_access('access content'), 'type' => MENU_CALLBACK ); $items[] = array( 'path' => 'panels/common/ajax', 'title' => t('ajax'), 'callback' => 'panels_ajax_passthru', 'callback arguments' => array('panels_common_ajax'), 'access' => user_access('access content'), 'type' => MENU_CALLBACK ); $items[] = array( 'path' => 'panels/ajax/add-content', 'title' => t('ajax'), 'callback' => 'panels_ajax_passthru', 'callback arguments' => array('panels_ajax_add_content'), 'access' => user_access('access content'), 'type' => MENU_CALLBACK ); $items[] = array( 'path' => 'panels/ajax/add-config', 'title' => t('ajax'), 'callback' => 'panels_ajax_passthru', 'callback arguments' => array('panels_ajax_add_config'), 'access' => user_access('access content'), 'type' => MENU_CALLBACK ); $items[] = array( 'path' => 'panels/ajax/configure', 'title' => t('ajax'), 'callback' => 'panels_ajax_passthru', 'callback arguments' => array('panels_ajax_configure'), 'access' => user_access('access content'), 'type' => MENU_CALLBACK ); $items[] = array( 'path' => 'panels/ajax/panel_settings', 'title' => t('ajax'), 'callback' => 'panels_ajax_passthru', 'callback arguments' => array('panels_common_panel_settings_ajax'), 'access' => user_access('access content'), 'type' => MENU_CALLBACK ); } return $items; } /** * Helper function for our AJAX stuff to call through to the right location */ function panels_ajax_passthru() { $args = func_get_args(); $callback = array_shift($args); if (arg(1) == 'common') { include_once './' . panels_get_path('includes/common.inc'); } else { include_once './' . panels_get_path('includes/display_edit.inc'); } return call_user_func_array($callback, $args); } /** * Simple render function to make sure output is what we want. * @ingroup panels_ajax */ function panels_ajax_render($output = NULL, $title = NULL, $url = NULL) { if (!is_object($output)) { $temp = new stdClass(); $temp->output = $output; $temp->type = 'display'; $temp->title = $title; $temp->url = $url; $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; } /** * panels path helper function */ function panels_get_path($file, $base_path = false, $module = 'panels') { if ($base_path) { $output = base_path(); } return $output . drupal_get_path('module', $module) . '/' . $file; } /** * Implementation of hook_perm */ function panels_perm() { return array('view all panes', 'administer pane visibility', 'administer advanced pane settings'); } // --------------------------------------------------------------------------- // panels custom image button /** * Custom form element to do our nice images. */ function panels_elements() { $type['panels_imagebutton'] = array('#input' => TRUE, '#button_type' => 'submit',); return $type; } /** * Theme our image button. */ function theme_panels_imagebutton($element) { return '\n"; } function panels_imagebutton_value() { // null function guarantees default_value doesn't get moved to #value. } /** * Add a single button to a form. */ function panels_add_button($image, $name, $text, $class, $id = NULL) { return array( '#type' => 'panels_imagebutton', '#image' => panels_get_path('images/' . $image), '#title' => $text, '#default_value' => $name, '#class' => $class, '#id' => $id, ); } // --------------------------------------------------------------------------- // cache handling stuff for display editing /** * Get a display from the cache; this is used if the display is currently * being edited, which can be a seriously multi-step process. */ function panels_cache_get($did) { static $cache = array(); if (!array_key_exists($did, $cache)) { $data = cache_get(session_id() . ':' . $did, 'cache'); $cache[$did] = unserialize($data->data); } return $cache[$did]; } /** * Save the edited display into the cache. */ function panels_cache_set($did, $cache) { cache_set(session_id() . ':' . $did, 'cache', serialize($cache), time() + 86400); } /** * Clear a display from the cache; used if the editing is aborted. */ function panels_cache_clear($did) { cache_clear_all(session_id() . ':' . $did, 'cache'); } // --------------------------------------------------------------------------- // cache handling stuff for non-display objects. /** * Get an object from cache. */ function panels_common_cache_get($obj, $did) { static $cache = array(); if (!array_key_exists($did, $cache)) { $data = cache_get(session_id() . ":$obj:$did", 'cache'); $cache[$did] = unserialize($data->data); } return $cache[$did]; } /** * Save the edited display into the cache. */ function panels_common_cache_set($obj, $did, $cache) { cache_set(session_id() . ":$obj:$did", 'cache', serialize($cache), time() + 86400); } /** * Clear a display from the cache; used if the editing is aborted. */ function panels_common_cache_clear($did) { cache_clear_all(session_id() . ":$obj:$did", 'cache'); } /** * Global storage function, used mostly so that _submit hooks can pass data * back to their originator more easily. */ function panels_set($var, $value = NULL) { static $vars = array(); if ($value !== NULL) { $vars[$var] = $value; } return $vars[$var]; } /** * Retrieve from global storage */ function panels_get($var) { return panels_set($var); } // --------------------------------------------------------------------------- // panels display editing /** * Main API entry point to edit a panel display. * * TODO: Doc this. Important. */ function panels_edit($display, $destination, $content_types = NULL) { include_once './' . panels_get_path('includes/display_edit.inc'); return _panels_edit($display, $destination, $content_types); } /** * Shortcut to the panels layout editor * * TODO: Doc this. Important. */ function panels_edit_layout($display, $finish, $destination) { include_once './' . panels_get_path('includes/display_edit.inc'); return drupal_get_form('panels_choose_layout', $display, $finish, $destination); } /** * Shortcut to the panels layout settings editor * * TODO: Doc this. Important. */ function panels_edit_layout_settings($display, $finish, $destination) { include_once './' . panels_get_path('includes/display_edit.inc'); return drupal_get_form('panels_edit_layout_settings_form', $display, $finish, $destination); } // --------------------------------------------------------------------------- // panels database functions /** * Forms the basis of a panel display */ class panels_display { var $args = array(); var $incoming_content = NULL; var $css_id = NULL; var $context = array(); } /** * Forms the basis for describing and storing a context that a display * might be running in. */ class panels_context { var $type = NULL; var $data = NULL; function panels_context($type = 'none', $data = NULL) { $this->type = $type; $this->data = $data; $this->title = t('Unknown context'); } function is_type($type) { $a = is_array($type) ? $type : array($type); $b = is_array($this->type) ? $this->type : array($this->type); return (bool) array_intersect($a, $b); } } /** * 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 = 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; } /** * Load a display from the database */ function panels_load_displays($dids) { $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(); 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) { $displays = panels_load_displays(array($did)); 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, subtype, configuration, access, position) VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', %d)", $pane->pid, $display->did, $pane->panel, $pane->type, $pane->subtype, 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) { 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); } /** * 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', 'subtype', '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; } /** * 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 */ function panels_render_display(&$display) { $layout = panels_get_layout($display->layout); if (!$layout) { return NULL; } // TODO: This may not be necessary now. Check this. panels_sanitize_display($display); $output = ''; // Let modules act just prior to render. foreach (module_implements('panels_pre_render') as $module) { $function = $module . '_panels_pre_render'; $output .= $function($display); } $output .= panels_render_layout($layout, $display, $display->css_id, $display->layout_settings); // Let modules act just prior to render. foreach (module_implements('panels_post_render') as $module) { $function = $module . '_panels_post_render'; $output .= $function($display); } 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) * @render */ 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. * @render */ 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)) { $content = panels_render_panes($content); } $output = theme($layout['theme'], check_plain($css_id), $content, $settings); return $output; } /** * Render all the panes in a display into a $content array to be used by * the display theme function. */ function panels_render_panes($display) { // First, render all the panes into little boxes. We do this here because // some panes request to be rendered after other panes (primarily so they // can do the leftovers of forms). $panes = array(); $later = array(); foreach ($display->content as $pid => $pane) { // If the user can't see this pane, do not render it. if (!panels_pane_access($pane)) { continue; } // If this pane wants to render last, add it to the $later array. $content_type = panels_get_content_type($pane->type); if (!empty($content_type['render last'])) { $later[$pid] = $pane; continue; } $panes[$pid] = panels_render_pane($display, $pane); } foreach ($later as $pid => $pane) { $panes[$pid] = panels_render_pane($display, $pane); } // Loop through all panels, put all panes that belong to the current panel // in an array, then render the panel. Primarily this ensures that the // panes are in the proper order. $content = array(); foreach ($display->panels as $panel_name => $pids) { $panel = array(); foreach ($pids as $pid) { if (!empty($panes[$pid])) { $panel[$pid] = $panes[$pid]; } } $content[$panel_name] = panels_render_panel($display, $panel); } return $content; } /** * Render a single pane, identifying its context, and put it into * the $panes array. */ function panels_render_pane(&$display, $pane) { // Identify which of our possible contexts apply. $context = NULL; if ($pane->subtype) { $content_type = panels_ct_get_types($pane->type); if (!empty($content_type[$pane->subtype]['required context'])) { if (isset($pane->configuration['context']) && isset($display->context[$pane->configuration['context']])) { $context = &$display->context[$pane->configuration['context']]; } // Don't display this pane if a context is required and not found. else { return; } } } return panels_get_pane_content($pane, $display->args, $context, $display->incoming_content); } /** * 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 $display * A display object. * @param $panes * An array of panes that are assigned to the panel that's being rendered. * @return * The rendered HTML for a panel. * @render */ function panels_render_panel($display, $panes) { if (!empty($display->panel_settings)) { $style = panels_get_style($display->panel_settings['style']); } else { $style = panels_get_style('default'); }; // 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. $panel_id = 0; if (isset($display->owner) && is_object($display->owner) && isset($display->owner->pid)) { $panel_id = $display->owner->pid; } return theme($style['render panel'], $display, $panel_id, $panes, $display->panel_settings['style_settings']); } /** * @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. * @param $context * The panels_context object. * @Param $incoming_content * Any incoming content, if this display is a wrapper. */ function panels_ct_get_title($type, $conf, $context = NULL, $incoming_content = NULL) { if ($function = panels_ct_function($type, 'title callback')) { return $function($conf, $context, $incoming_content); } } /** * Create the basic config form */ function panels_ct_conf_form($type, $id, $contexts, $conf) { $content_type = panels_ct_get_types($type); $count = 0; $saved_cid = NULL; if (!empty($content_type[$id]['required context']) && is_array($contexts)) { // See which of these contexts are valid foreach ($contexts as $cid => $context) { if ($context->is_type($content_type[$id]['required context'])) { $options[$cid] = $context->title; $saved_cid = $cid; $count++; } } } $form = array(); if ($count == 1) { $form['context'] = array( '#type' => 'value', '#value' => $saved_cid, ); } else if (!empty($options)) { $form['context'] = array( '#type' => 'select', '#options' => $options, '#title' => t('Context'), '#description' => t('Multiple contexts are valid for this pane; one must be chosen.'), '#default_value' => $conf['context'], ); } return $form; } /** * 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 $contexts * A list of possible contexts. * @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, $contexts, $parents) { $form = panels_ct_conf_form($type, $id, $contexts, array()); if ($function = panels_ct_function($type, 'add callback')) { $result = $function($id, $parents); if (is_array($result)) { $form += $result; } } return $form; } /** * 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, $subtype, $contexts, $conf, $parents) { $form = panels_ct_conf_form($type, $subtype, $contexts, $conf); if ($function = panels_ct_function($type, 'edit callback')) { $result = $function($subtype, $parents, $conf); if (is_array($result)) { $form += $result; } } return $form; } /** * 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 a list of panels available in the layout. @layout */ 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(); } /** * 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 $has_content * Whether or not the display will have incoming content * @param $allowed_types * An array of content allowed keyed boy content_type . '-' . sub_type * @param $default_types * A default allowed/denied status for content that isn't known about */ function panels_get_available_content_types($contexts = NULL, $has_content = FALSE, $allowed_types = NULL, $default_types = NULL) { $content_types = panels_get_content_types(); $available = array(); foreach ($content_types as $id => $type) { foreach (panels_ct_get_types($type) as $cid => $cinfo) { // exclude items that require content if we're saying we don't // provide it. if (!empty($cinfo['requires content']) && !$has_content) { continue; } // Check to see if the content type can be used in this context. if (!empty($cinfo['required context'])) { if (empty($contexts)) { continue; } foreach ($contexts as $context) { if (!$context->is_type($cinfo['required context'])) { // This context does not match; continue the foreach above us. continue 2; } } } // Check to see if the passed-in allowed types allows this content. if ($allowed_types) { $key = $id . '-' . $cid; if (!isset($allowed_types[$key])) { $allowed_types[$key] = isset($default_types[$id]) ? $default_types[$id] : $default_types['other']; } if (!$allowed_types[$key]) { continue; } } // If we made it through all the tests, then we can use this content. $available[$id][$cid] = $cinfo; } } return $available; } /** * Get an array of all content types that can be fed into the * display editor for the add content list, regardless of * availability. * */ function panels_get_all_content_types() { $content_types = panels_get_content_types(); $available = array(); foreach ($content_types as $id => $type) { foreach (panels_ct_get_types($type) as $cid => $cinfo) { // If we made it through all the tests, then we can use this content. $available[$id][$cid] = $cinfo; } } return $available; } // ------------------------------------------------------------------ // 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, $context = NULL, $incoming_content = NULL) { return panels_ct_get_title($pane->type, $pane->configuration, $context, $incoming_content); } /** * @} End of "defgroup panels_content". */ // --------------------------------------------------------------------------- // panels argument helpers function panels_argument_function($type, $name) { if (is_object($type)) { $argument = $type; } else { $argument = panels_get_argument($type); } $function = $argument[$name]; if (function_exists($function)) { return $function; } } function panels_argument_get_context($type, $arg, $conf, $selector, $index = 0) { $argument = panels_get_argument($type); if ($function = $argument['context']) { $context = $function($arg, $conf, $selector, $index); if ($context) { $context->title = $argument['title'] . ' ' . $conf['id']; return $context; } } } function panels_argument_get_title($type, $context) { if ($function = panels_argument_function($type, 'title function')) { return $function($context); } } function panels_argument_choose_display($type, $conf, $context) { if ($function = panels_argument_function($type, 'choose display')) { return $function($conf, $context); } } // --------------------------------------------------------------------------- // panels data loading /** * Load plugins from a directory. * * @param $directory * The directory to choose; also the plugin type. * @param $hook * The name of the hook to be invoked. * @param $file * The file to load if we're looking for just one particular plugin. * * @return * An array of information created for this plugin. */ function panels_load_includes($directory, $hook, $file = NULL) { // Load all our plugins. $path = panels_get_path($directory); $files = drupal_system_listing("$file" . '.inc$', $path, 'name', 0); $info = array(); foreach($files as $file) { require_once('./' . $file->filename); $result = _panels_process_plugin('panels', 'panels_' . $file->name, dirname($file->filename), $hook); if (is_array($result)) { $info = array_merge($info, $result); } } return $info; } /** * Load plugin info for all hooks; this is handled separately from plugins * from files. This is cached so we don't find ourselves building htis * repeatedly. * * @param $hook * The hook being invoked. * * @return * An array of info supplied by any hook implementations. */ function panels_load_hooks($hook) { $info = array(); foreach (module_implements($hook) as $module) { $result = _panels_process_plugin($module, $module, drupal_get_path('module', $module), $hook); if (is_array($result)) { $info = array_merge($info, $result); } } return $info; } /** * Process a single hook implementation of a panels plugin. * * @param $module * The module that owns the hook. * @param $identifier * Either the module or 'panels_' . $file->name * @param $hook * The name of the hook being invoked. */ function _panels_process_plugin($module, $identifier, $path, $hook) { $function = $identifier . '_' . $hook; if (!function_exists($function)) { return NULL; } $result = $function(); if (!isset($result) || !is_array($result)) { return NULL; } // Fill in defaults. foreach ($result as $name => $plugin) { $result[$name]['module'] = $module; $result[$name]['name'] = $name; $result[$name]['path'] = $path; } return $result; } /** * Fetch a group of plugins by name. * * @param $plugin * This is the name of the plugin, and also the name of the directory. * @param $hook * This is the hook to call to get the info for the plugin. * * @return * An array of information arrays about the plugins received. */ function panels_get_plugins($plugin, $hook, $id = NULL) { static $plugins = array(); static $all_hooks = array(); static $all_files = array(); // Always load all hooks if we need them. if (!isset($all_hooks[$plugin])) { $all_hooks[$plugin] = TRUE; $plugins[$plugin] = panels_load_hooks($hook); // TODO: DEPRECATED. Put in to make the transition easier! This WILL // disappear by alpha 11. if ($plugin == 'styles') { $plugins[$plugin] = array_merge($plugins[$plugin], panels_load_hooks('panels_panel_style_info')); } } // First, see if it's in our hooks before we even bother. if ($id && array_key_exists($id, $plugins[$plugin])) { return $plugins[$plugin][$id]; } // Then see if we should load all files. We only do this if we're // want a list of all plugins. if (!$id && empty($all_files[$plugin])) { $all_files[$plugin] = TRUE; $plugins[$plugin] = array_merge($plugins[$plugin], panels_load_includes($plugin, $hook)); } // If no id was requested, we are finished here: if (!$id) { return $plugins[$plugin]; } // Check to see if we need to look for the file if (!array_key_exists($id, $plugins[$plugin])) { $result = panels_load_includes($plugin, $hook, $id); // Set to either what was returned or NULL. $plugins[$plugin][$id] = isset($result[$id]) ? $result[$id] : NULL; } // At this point we should either have the plugin, or a NULL. return $plugins[$plugin][$id]; } /** * Fetch a layout plugin * * @param $layout * Name of a panel layout. * @return * An array with information about the requested panel layout. */ function panels_get_layout($layout) { return panels_get_plugins('layouts', 'panels_layouts', $layout); } /** * Fetch all layout plugins * * @return * An array of arrays with information about all available panel layouts. */ function panels_get_layouts() { return panels_get_plugins('layouts', 'panels_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_style($style) { return panels_get_plugins('styles', 'panels_styles', $style); } /** * Collate information about all available panel styles. * * @return * An array of arrays with information about all available panel styles. */ function panels_get_styles() { return panels_get_plugins('styles', 'panels_styles'); } /** * Collate information about a specific panel argument. * * @param $argument * Name of a panel argument. * @return * An array with information about the requested panel argument. */ function panels_get_argument($argument) { return panels_get_plugins('arguments', 'panels_arguments', $argument); } /** * Collate information about all available panel arguments. * * @return * An array of arrays with information about all available panel arguments. */ function panels_get_arguments() { return panels_get_plugins('arguments', 'panels_arguments'); } /** * Fetch a content_type plugin * * @param $content type * Name of a panel content type. * @return * An array with information about the requested panel content type. */ function panels_get_content_type($content_type) { return panels_get_plugins('content_types', 'panels_content_types', $content_type); } /** * Fetch all content type plugins * * @return * An array of arrays with information about all available panel content types. */ function panels_get_content_types() { return panels_get_plugins('content_types', 'panels_content_types'); } // @render function theme_panels_pane($block, $display) { if (!empty($block->content)) { $output = '