$plugin['title'], 'description' => $plugin['description'], 'icon' => ctools_content_admin_icon($plugin), 'category' => $plugin['category'], ); if (isset($plugin['required context'])) { $type['required context'] = $plugin['required context']; } if (isset($plugin['top level'])) { $type['top level'] = $plugin['top level']; } $plugin['content types'] = array($plugin['name'] => $type); if (!isset($plugin['single'])) { $plugin['single'] = TRUE; } } } } /** * Fetch metadata on a specific content_type plugin. * * @param mixed $content * Name of a panel content type. * * @return * An array with information about the requested panel content type. */ function ctools_get_content_type($content_type) { ctools_include('context'); ctools_include('plugins'); return ctools_get_plugins('ctools', 'content_types', $content_type); } /** * Fetch metadata for all content_type plugins. * * @return * An array of arrays with information about all available panel content types. */ function ctools_get_content_types() { ctools_include('context'); ctools_include('plugins'); return ctools_get_plugins('ctools', 'content_types'); } /** * Get all of the individual subtypes provided by a given content type. 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. * * @return * An array of all subtypes available. */ function ctools_content_get_subtypes($type) { static $cache = array(); $subtypes = array(); if (is_array($type)) { $plugin = $type; } else { $plugin = ctools_get_content_type($type); } if (empty($plugin) || empty($plugin['name'])) { return; } if (isset($cache[$plugin['name']])) { return $cache[$plugin['name']]; } if (isset($plugin['content types'])) { $function = $plugin['content types']; if (is_array($function)) { $subtypes = $function; } elseif (function_exists($function)) { // Cast to array to prevent errors from non-array returns. $subtypes = (array) $function($plugin); } } // Walk through the subtypes and ensure minimal settings are // retained. foreach ($subtypes as $id => $subtype) { // Ensure that the 'subtype_id' value exists. if (!isset($subtype['subtype_id'])) { $subtypes[$id]['subtype_id'] = $id; } // Use exact name since this is a modify by reference. ctools_content_prepare_subtype($subtypes[$id], $plugin); } $cache[$plugin['name']] = $subtypes; return $subtypes; } /** * Given a content type and a subtype id, return the information about that * content subtype. * * @param $type * The content type being fetched. * @param $subtype_id * The id of the subtype being fetched. * * @return * An array of information describing the content subtype. */ function ctools_content_get_subtype($type, $subtype_id) { $subtype = array(); if (is_array($type)) { $plugin = $type; } else { $plugin = ctools_get_content_type($type); } $function = ctools_plugin_get_function($plugin, 'content type'); if ($function) { $subtype = $function($subtype_id, $plugin); } else { $subtypes = ctools_content_get_subtypes($type); if (isset($subtypes[$subtype_id])) { $subtype = $subtypes[$subtype_id]; } // If there's only 1 and we somehow have the wrong subtype ID, do not // care. Return the proper subtype anyway. if (empty($subtype) && !empty($plugin['single'])) { $subtype = current($subtypes); } } if ($subtype) { // Ensure that the 'subtype_id' value exists. This is also done in // ctools_content_get_subtypes(), but it wouldn't be called if the plugin // provides the subtype through its own function. if (!isset($subtype['subtype_id'])) { $subtype['subtype_id'] = $subtype_id; } ctools_content_prepare_subtype($subtype, $plugin); } return $subtype; } /** * Ensure minimal required settings on a content subtype exist. */ function ctools_content_prepare_subtype(&$subtype, $plugin) { foreach (array('path', 'js', 'css') as $key) { if (!isset($subtype[$key]) && isset($plugin[$key])) { $subtype[$key] = $plugin[$key]; } } // Trigger hook_ctools_content_subtype_alter(). drupal_alter('ctools_content_subtype', $subtype, $plugin); } /** * Get the content from a given content type. * * @param $type * The content type. May be the name or an already loaded content type plugin. * @param $subtype * The name of the subtype being rendered. * @param $conf * The configuration for the content type. * @param $keywords * An array of replacement keywords that come from outside contexts. * @param $args * The arguments provided to the owner of the content type. Some content may * wish to configure itself based on the arguments the panel or dashboard * received. * @param $context * An array of context objects available for use. * @param $incoming_content * Any incoming content, if this display is a wrapper. * * @return * The content as rendered by the plugin, or NULL. * This content should be an object with the following possible properties: * - title: The safe to render title of the content. * - title_heading: The title heading. * - content: The safe to render HTML content. * - links: An array of links associated with the content suitable for * theme('links'). * - more: An optional 'more' link (destination only) * - admin_links: Administrative links associated with the content, suitable * for theme('links'). * - feeds: An array of feed icons or links associated with the content. * Each member of the array is rendered HTML. * - type: The content type. * - subtype: The content subtype. These two may be used together as * module-delta for block style rendering. */ function ctools_content_render($type, $subtype, $conf, $keywords = array(), $args = array(), $context = array(), $incoming_content = '') { if (is_array($type)) { $plugin = $type; } else { $plugin = ctools_get_content_type($type); } $subtype_info = ctools_content_get_subtype($plugin, $subtype); $function = ctools_plugin_get_function($subtype_info, 'render callback'); if (!$function) { $function = ctools_plugin_get_function($plugin, 'render callback'); } if ($function) { $pane_context = ctools_content_select_context($plugin, $subtype, $conf, $context); if ($pane_context === FALSE) { return; } $content = $function($subtype, $conf, $args, $pane_context, $incoming_content); if (empty($content)) { return; } // Set up some defaults and other massaging on the content before we hand // it back to the caller. if (!isset($content->type)) { $content->type = $plugin['name']; } if (!isset($content->subtype)) { $content->subtype = $subtype; } // Override the title if configured to. if (!empty($conf['override_title'])) { // Give previous title as an available substitution here. $keywords['%title'] = empty($content->title) ? '' : $content->title; $content->original_title = $keywords['%title']; $content->title = $conf['override_title_text']; $content->title_heading = isset($conf['override_title_heading']) ? $conf['override_title_heading'] : 'h2'; } if (!empty($content->title)) { // Perform substitutions. if (!empty($keywords) || !empty($context)) { $content->title = ctools_context_keyword_substitute($content->title, $keywords, $context); } // Sterilize the title. $content->title = filter_xss_admin($content->title); // If a link is specified, populate. if (!empty($content->title_link)) { if (!is_array($content->title_link)) { $url = array('href' => $content->title_link); } else { $url = $content->title_link; } // Set defaults so we don't bring up notices. $url += array('href' => '', 'attributes' => array(), 'query' => array(), 'fragment' => '', 'absolute' => NULL, 'html' => TRUE); $content->title = l($content->title, $url['href'], $url); } } return $content; } } /** * Determine if a content type can be edited or not. * * Some content types simply have their content and no options. This function * lets a UI determine if it should display an edit link or not. */ function ctools_content_editable($type, $subtype, $conf) { if (empty($type['edit form']) && empty($subtype['edit form'])) { return FALSE; } $function = FALSE; if (!empty($subtype['check editable'])) { $function = ctools_plugin_get_function($subtype, 'check editable'); } elseif (!empty($type['check editable'])) { $function = ctools_plugin_get_function($type, 'check editable'); } if ($function) { return $function($type, $subtype, $conf); } return TRUE; } /** * Get the administrative title from a given content type. * * @param $type * The content type. May be the name or an already loaded content type object. * @param $subtype * The subtype being rendered. * @param $conf * The configuration for the content type. * @param $context * An array of context objects available for use. These may be placeholders. */ function ctools_content_admin_title($type, $subtype, $conf, $context = NULL) { if (is_array($type)) { $plugin = $type; } elseif (is_string($type)) { $plugin = ctools_get_content_type($type); } else { return; } if ($function = ctools_plugin_get_function($plugin, 'admin title')) { $pane_context = ctools_content_select_context($plugin, $subtype, $conf, $context); if ($pane_context === FALSE) { if ($plugin['name'] == $subtype) { return t('@type will not display due to missing context', array('@type' => $plugin['name'])); } return t('@type:@subtype will not display due to missing context', array('@type' => $plugin['name'], '@subtype' => $subtype)); } return $function($subtype, $conf, $pane_context); } elseif (isset($plugin['admin title'])) { return $plugin['admin title']; } elseif (isset($plugin['title'])) { return $plugin['title']; } } /** * Get the proper icon path to use, falling back to default icons if no icon exists. * * $subtype * The loaded subtype info. */ function ctools_content_admin_icon($subtype) { $icon = ''; if (isset($subtype['icon'])) { $icon = $subtype['icon']; if (!file_exists($icon)) { $icon = $subtype['path'] . '/' . $icon; } } if (empty($icon) || !file_exists($icon)) { $icon = ctools_image_path('no-icon.png'); } return $icon; } /** * Set up the default $conf for a new instance of a content type. */ function ctools_content_get_defaults($plugin, $subtype) { if (isset($plugin['defaults'])) { $defaults = $plugin['defaults']; } elseif (isset($subtype['defaults'])) { $defaults = $subtype['defaults']; } if (isset($defaults)) { if (is_string($defaults) && function_exists($defaults)) { if ($return = $defaults($pane)) { return $return; } } elseif (is_array($defaults)) { return $defaults; } } return array(); } /** * Get the administrative title from a given content type. * * @param $type * The content type. May be the name or an already loaded content type object. * @param $subtype * The subtype being rendered. * @param $conf * The configuration for the content type. * @param $context * An array of context objects available for use. These may be placeholders. */ function ctools_content_admin_info($type, $subtype, $conf, $context = NULL) { if (is_array($type)) { $plugin = $type; } else { $plugin = ctools_get_content_type($type); } if ($function = ctools_plugin_get_function($plugin, 'admin info')) { $output = $function($subtype, $conf, $context); } if (empty($output) || !is_object($output)) { $output = new stdClass(); // Replace the _ with " " for a better output. $subtype = check_plain(str_replace("_", " ", $subtype)); $output->title = $subtype; $output->content = t('No info available.'); } return $output; } /** * Add the default FAPI elements to the content type configuration form. */ function ctools_content_configure_form_defaults($form, &$form_state) { $plugin = $form_state['plugin']; $subtype = $form_state['subtype']; $contexts = isset($form_state['contexts']) ? $form_state['contexts'] : NULL; $conf = $form_state['conf']; $add_submit = FALSE; if (!empty($subtype['required context']) && is_array($contexts)) { $form['context'] = ctools_context_selector($contexts, $subtype['required context'], isset($conf['context']) ? $conf['context'] : array()); $add_submit = TRUE; } ctools_include('dependent'); // Unless we're not allowed to override the title on this content type, add this // gadget to all panes. if (empty($plugin['no title override']) && empty($subtype['no title override'])) { $form['aligner_start'] = array( '#markup' => '