t('Custom content'), 'no title override' => TRUE, 'defaults' => array('admin_title' => '', 'title' => '', 'body' => '', 'format' => filter_fallback_format(), 'substitute' => TRUE), 'js' => array('misc/autocomplete.js', 'misc/textarea.js', 'misc/collapse.js'), // Make sure the edit form is only used for some subtypes. 'edit form' => '', 'add form' => '', 'edit text' => t('Edit'), 'all contexts' => TRUE, ); /** * Return the custom content types with the specified $subtype_id. */ function ctools_custom_content_type_content_type($subtype_id) { if ($subtype_id == 'custom') { return _ctools_default_content_type_content_type(); } else { ctools_include('export'); $content = ctools_export_crud_load('ctools_custom_content', $subtype_id); if ($content) { return _ctools_custom_content_type_content_type($content); } } } /** * Return all custom content types available. */ function ctools_custom_content_type_content_types() { ctools_include('export'); $types = array(); $types['custom'] = _ctools_default_content_type_content_type(); foreach (ctools_export_crud_load_all('ctools_custom_content') as $name => $content) { $types[$name] = _ctools_custom_content_type_content_type($content); } return $types; } /** * Settings for the default custom content type. * * The default is the one that allows the user to actually create a type. */ function _ctools_default_content_type_content_type() { $info = array( 'name' => 'custom', 'title' => t('New custom content'), 'top level' => TRUE, 'category' => t('Custom'), 'description' => t('Create a completely custom piece of HTML content.'), 'edit form' => 'ctools_custom_content_type_edit_form', 'all contexts' => TRUE, 'check editable' => 'ctools_custom_content_type_editable', ); return $info; } /** * Return an info array for a specific custom content type. */ function _ctools_custom_content_type_content_type($content) { $info = array( 'name' => $content->name, 'title' => check_plain($content->admin_title), 'description' => check_plain($content->admin_description), 'category' => $content->category ? check_plain($content->category) : t('Miscellaneous'), 'all contexts' => TRUE, 'icon' => 'icon_block_custom.png', // Store this here to make it easy to access. 'content' => $content, ); return $info; } /** * Given a subtype and a $conf, return the actual settings to use. * * The actual settings may be stored directly in the pane or this may * be a pointer to re-usable content that may be in the database or in * an export. We have to determine from the subtype whether or not it * is local or shared custom content. */ function ctools_custom_content_type_get_conf($subtype, $conf) { if ($subtype['name'] != 'custom') { $settings = $subtype['content']->settings; $settings['custom_type'] = 'fixed'; $settings['content'] = $subtype['content']; } else { // This means they created it as custom content and then set it as // reusable. Since we're not allowed to change the subtype, we're // still stored as though we are local, but are pointing off to // non-local. if (!empty($conf['name'])) { ctools_include('export'); $content = ctools_export_crud_load('ctools_custom_content', $conf['name']); if ($content) { $settings = $content->settings; $settings['custom_type'] = 'fixed'; $settings['content'] = $content; $settings['admin_title'] = $content->admin_title; } else { $content = ctools_export_crud_new('ctools_custom_content'); $content->name = $conf['name']; $settings = array( 'admin_title' => t('Missing/deleted content'), 'title' => '', 'body' => '', 'format' => filter_fallback_format(), 'substitute' => TRUE, 'custom_type' => 'fixed', 'content' => $content, ); } } // This means that it is created as custom and has not been set to // reusable. else { $settings = $conf; $settings['custom_type'] = 'local'; } } return $settings; } function ctools_custom_content_type_editable($content_type, $subtype, $conf) { if ($subtype['name'] == 'custom' && !empty($conf['name'])) { return FALSE; } return TRUE; } /** * Output function for the 'custom' content type. Outputs a custom * based on the module and delta supplied in the configuration. */ function ctools_custom_content_type_render($subtype, $conf, $args, $contexts) { $settings = ctools_custom_content_type_get_conf(ctools_custom_content_type_content_type($subtype), $conf); static $delta = 0; $block = new stdClass(); $block->subtype = ++$delta; $block->title = filter_xss_admin($settings['title']); // Add keyword substitutions if we were configured to do so. $content = $settings['body']; if (!empty($contexts) && !empty($settings['substitute'])) { $content = ctools_context_keyword_substitute($content, array(), $contexts); } $block->content = check_markup($content, $settings['format']); return $block; } /** * Callback to provide the administrative title of the custom content. */ function ctools_custom_content_type_admin_title($subtype, $conf) { $settings = ctools_custom_content_type_get_conf(ctools_custom_content_type_content_type($subtype), $conf); $output = t('Custom'); $title = !empty($settings['admin_title']) ? $settings['admin_title'] : $settings['title']; if ($title) { if ($settings['custom_type'] != 'fixed') { $output = t('Custom: @title', array('@title' => $title)); } else { $output = $title; } } return $output; } /** * Callback to provide administrative info. In this case we'll render the * content as long as it's not PHP, which is too risky to render here. */ function ctools_custom_content_type_admin_info($subtype, $conf) { $settings = ctools_custom_content_type_get_conf(ctools_custom_content_type_content_type($subtype), $conf); $block = new stdClass(); $block->title = filter_xss_admin($settings['title']); // We don't want to render php output on preview here, because if something is // wrong the whole display will be borked. So we check to see if the php // evaluator filter is being used, and make a temporary change to the filter // so that we get the printed php, not the eval'ed php. $php_filter = FALSE; foreach (filter_list_format($settings['format']) as $filter) { if ($filter->module == 'php') { $php_filter = TRUE; break; } } // If a php filter is active, just print the source, but only if the current // user has access to the actual filter. if ($php_filter) { $filter = filter_format_load($settings['format']); if (!filter_access($filter)) { return NULL; } $block->content = '
'. check_plain($settings['body']) .'
'; } else { // We also need to filter through XSS admin because