list_layouts() as $layout_name) { $this->allowed_layout_settings[$layout_name] = $start_allowed ? 1 : 0; } } /** * Manage panels_common_set_allowed_layouts(), the FAPI code for selecting allowed layouts. * * MAKE SURE to set panels_allowed_layouts::allow_new before calling this method. If you want the panels API * to handle saving these allowed layout settings, panels_allowed_layouts::module_name must also be set. * * Below is a sample implementation; refer to the rest of the class documentation to understand all the * specific pieces. Values that are intended to be replaced are wrapped with <>. * * \n @code * function docdemo_allowed_layouts() { * panels_load_include('common'); * if (!is_a($allowed_layouts = unserialize(variable_get('panels_common_allowed_layouts', serialize(''))), 'panels_allowed_layouts')) { * $allowed_layouts = new panels_allowed_layouts(); * $allowed_layouts->allow_new = TRUE; * $allowed_layouts->module_name = ''; * } * $result = $allowed_layouts->set_allowed(''); * if (in_array($allowed_layouts->form_state, array('failed-validate', 'render'))) { * return $result; * } * elseif ($allowed_layouts->form_state == 'submit') { * drupal_goto(''); * } * } * @endcode \n * * If $allowed_layouts->form_state == 'failed-validate' || 'render', then you'll need to return * $result as it contains the structured form HTML generated by drupal_render_form() and is ready * to be passed through index.php's call to theme('page', ...). * * However, if $allowed_layouts->form_state == 'submit', then the form has been submitted and we should * react. It's really up to your client module how you handle the rest; panels_allowed_layouts::save() (or * panels_allowed_layouts::api_save(), if that's the route you're going) will have already been called, * so if those methods handle your save routine, then all there is left to do is handle redirects, if you * want. The current implementation of the allowed layouts form currently never redirects, so it's up to * you to control where the user ends up next. * * @param string $title * Used to set the title of the allowed layouts form. If no value is given, defaults to * 'Panels: Allowed Layouts'. * * @return mixed $result * - On the first passthrough when the form is being rendered, $result is the form's structured * HTML, ready to be pushed to the screen with a call to theme('page', ...). * - A successful second passthrough indicates a successful submit, and * $result === panels_allowed_layouts::allowed_layout_settings. Returning it is simply for convenience. */ function set_allowed($title = 'Panels: Allowed Layouts') { $this->sync_with_available(); $form_id = 'panels_common_set_allowed_layouts'; $form = drupal_retrieve_form($form_id, $this, $title); if ($result = drupal_process_form($form_id, $form)) { // successful submit $this->form_state = 'submit'; return $result; } $this->form_state = isset($_POST['op']) ? 'failed-validate' : 'render'; $result = drupal_render_form($form_id, $form); return $result; } /** * Checks for newly-added layouts and deleted layouts. If any are found, updates panels_allowed_layouts::allowed_layout_settings; * new additions are made according to panels_allowed_layouts::allow_new, while deletions are unset(). * * Note that any changes made by this function are not saved in any permanent location. */ function sync_with_available() { $layouts = $this->list_layouts(); foreach (array_diff($layouts, array_keys($this->allowed_layout_settings)) as $new_layout) { $this->allowed_layout_settings[$new_layout] = $this->allow_new ? 1 : 0; } foreach (array_diff(array_keys($this->allowed_layout_settings), $layouts) as $deleted_layout) { unset($this->allowed_layout_settings[$deleted_layout]); } } /** * Use panels_allowed_layouts::module_name to generate a variable for variable_set(), in which * a serialized version of $this will be stored. * * Does nothing if panels_allowed_layouts::module_name is not set. * * IMPORTANT NOTE: if you use variable_get() in a custom client module save() method, you MUST * wrap $this in serialize(), then unserialize() what you get from variable_get(). Failure to * do so will result in an incomplete object. The following code will work: * @code * $allowed_layouts = unserialize(variable_get('your_variable_name', serialize('')); * @endcode * * If you don't serialize the second parameter of variable_get() and the variable name you provide * can't be found, an E_STRICT warning will be generated for trying to unserialize an entity * that has not been serialized. * */ function api_save() { if (!is_null($this->module_name)) { variable_set($this->module_name . "_allowed_layouts", serialize($this)); } } /** * Snag a list of the current layouts for internal use. * * Data is not saved in a class member in order to ensure that it's * fresh. * * @return array $layouts * An indexed array of the system names for all currently available layouts. */ function list_layouts() { static $layouts = array(); if (empty($layouts)) { panels_load_include('plugins'); $layouts = array_keys(panels_get_layouts()); } return $layouts; } } /** * A common settings page for Panels modules, because this code is relevant to * any modules that don't already have special requirements. */ function panels_common_settings(&$form_state, $module_name = 'panels_common') { panels_load_include('plugins'); $content_types = panels_get_content_types(); $default_types = variable_get($module_name . '_default', NULL); if (!isset($default_types)) { $default_types = array('block' => TRUE, 'views' => TRUE, 'other' => TRUE); $skip = TRUE; } foreach ($content_types as $id => $info) { if (empty($info['single'])) { $default_options[$id] = t('New @s', array('@s' => $info['title'])); } } $default_options['other'] = t('New content of other types'); $form['panels_common_default'] = array( '#type' => 'checkboxes', '#title' => t('New content behavior'), '#description' => t('Select the default behavior of new content added to the system. If checked, new content will automatically be immediately available to be added to Panels pages. If not checked, new content will not be available until specifically allowed here.'), '#options' => $default_options, '#default_value' => array_keys(array_filter($default_types)), ); if ($skip) { $form['markup'] = array('#value' => t('

Click Submit to be presented with a complete list of available content types set to the defaults you selected.

')); $form['skip'] = array('#type' => 'value', '#value' => TRUE); } else { // Rebuild the entire list, setting appropriately from defaults. Give // each type its own checkboxes set unless it's 'single' in which // case it can go into our fake other set. $available_content_types = panels_get_all_content_types(); $allowed_content_types = variable_get($module_name . '_allowed_types', array()); foreach ($available_content_types as $id => $types) { foreach ($types as $type => $info) { $key = $id . '-' . $type; $checkboxes = empty($content_types[$id]['single']) ? $id : 'other'; $options[$checkboxes][$key] = $info['title']; if (!isset($allowed_content_types[$key])) { $allowed[$checkboxes][$key] = isset($default_types[$id]) ? $default_types[$id] : $default_types['other']; } else { $allowed[$checkboxes][$key] = $allowed_content_types[$key]; } } } $form['content_types'] = array( '#tree' => TRUE, '#prefix' => '
', '#suffix' => '
', ); // cheat a bit $content_types['other'] = array('title' => t('Other'), 'weight' => 10); foreach ($content_types as $id => $info) { if (isset($allowed[$id])) { $form['content_types'][$id] = array( '#prefix' => '
', '#suffix' => '
', '#type' => 'checkboxes', '#title' => t('Allowed @s content', array('@s' => $info['title'])), '#options' => $options[$id], '#default_value' => array_keys(array_filter($allowed[$id])), ); } } } $form['module_name'] = array( '#type' => 'value', '#value' => $module_name, ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Submit'), ); drupal_add_css(panels_get_path('css/panels_page.css')); return $form; } /** * Submit hook for panels_common_settings */ function panels_common_settings_submit($form, &$form_state) { $module_name = $form_state['values']['module_name']; variable_set($module_name . '_default', $form_state['values']['panels_common_default']); if (!$form_state['values']['skip']) { // merge the broken apart array neatly back together variable_set($module_name . '_allowed_types', call_user_func_array('array_merge', $form_state['values']['content_types'])); } drupal_set_message(t('Your changes have been saved.')); } /** * Based upon the settings, get the allowed types for this node. */ function panels_common_get_allowed_types($module, $contexts = array(), $has_content = FALSE, $default_defaults = array(), $default_allowed_types = array()) { // Get a list of all types that are available $default_types = variable_get($module . '_defaults', $default_defaults); $allowed_types = variable_get($module . '_allowed_types', $default_allowed_types); // By default, if they haven't gone and done the initial setup here, // let all 'other' types (which will be all types) be available. if (!isset($default_types['other'])) { $default_types['other'] = TRUE; } panels_load_include('plugins'); $content_types = panels_get_available_content_types($contexts, $has_content, $allowed_types, $default_types); return $content_types; } /** * The FAPI code for generating an 'allowed layouts' selection form. * * NOTE: Because the Panels API does not guarantee a particular method of storing the data on allowed layouts, * it is not_possible for the Panels API to implement any checks that determine whether reductions in * the set of allowed layouts conflict with pre-existing layout selections. $displays in that category * will continue to function with their current layout as normal until the user/owner/admin attempts * to change layouts on that display, at which point they will have to select from the new set of * allowed layouts. If this is not the desired behavior for your client module, it's up to you to * write a validation routine that determines what should be done with conflicting layouts. * * Remember that changing layouts where panes have already been created can result in data loss; * consult panels_change_layout() to see how the Panels API handles that process. Running * drupal_execute('panels_change_layout', ...) is one possible starting point. * * @ingroup forms * * @param array $allowed_layouts * The set of allowed layouts that should be used as the default values * for this form. If none is provided, then by default no layouts will be restricted. * @param string $title * The title that will be used for the form. Defaults to 'Panels: Allowed Layouts' if * no value was provided in panels_allowed_layouts::set_allowed. */ // TODO need to add something that handles $finish & $destination-type stuff. function panels_common_set_allowed_layouts($allowed_layouts, $title) { $layouts = panels_get_layouts(); foreach ($layouts as $id => $layout) { $options[$id] = panels_print_layout_icon($id, $layout, check_plain($layout['title'])); } drupal_set_title($title); $form['variables'] = array('#type' => 'value', '#value' => array($allowed_layouts)); drupal_add_js(panels_get_path('js/layout.js')); $form['layouts'] = array( '#type' => 'checkboxes', '#title' => t('Select allowed layouts'), '#options' => $options, '#description' => t('Check the boxes for all layouts you want to allow users choose from when picking a layout. You must allow at least one layout.'), '#default_value' => array_keys(array_filter($allowed_layouts->allowed_layout_settings)), ); $form['clearer'] = array( // TODO: FIx this to use clear-block instead '#value' => '
', ); $form['#redirect'] = FALSE; $form['submit'] = array( '#type' => 'submit', '#value' => t('Save'), ); $form['#token'] = FALSE; return $form; } function panels_common_set_allowed_layouts_validate($form_id, $form_values, $form) { $selected = array_filter($form_values['layouts']); if (empty($selected)) { form_set_error('layouts', 'You must choose at least one layout to allow.'); } } function panels_common_set_allowed_layouts_submit($form_id, $form_values) { list($allowed_layouts) = $form_values['variables']; foreach ($form_values['layouts'] as $layout => $setting) { $allowed_layouts->allowed_layout_settings[$layout] = $setting === 0 ? 0 : 1; } method_exists($allowed_layouts, 'save') ? $allowed_layouts->save() : $allowed_layouts->api_save(); return $allowed_layouts->allowed_layout_settings; } /** * The layout information fieldset displayed at admin/edit/panel-%implementation%/add/%layout%. */ function panels_common_get_layout_information($panel_implementation, $contexts = array()) { $form = array(); panels_load_include('plugins'); $layout = panels_get_layout($panel_implementation->display->layout); $form = array( '#type' => 'fieldset', '#title' => t('Layout'), ); $form['layout-icon'] = array( '#value' => panels_print_layout_icon($panel_implementation->display->layout, $layout), ); $form['layout-display'] = array( '#value' => check_plain($layout['title']), ); $content = '
'; foreach (panels_get_panels($layout, $panel_implementation->display) as $panel_id => $title) { $content .= "
$title
"; if ($panel_implementation->display->panels[$panel_id]) { $content .= '
    '; foreach ($panel_implementation->display->panels[$panel_id] as $pid) { $content .= '
  1. '. panels_get_pane_title($panel_implementation->display->content[$pid], $contexts) .'
  2. '; } $content .= '
'; } else { $content .= t('Empty'); } $content .= '
'; } $content .= '
'; $form['layout-content'] = array( '#value' => $content, ); return $form; } /** * Create a visible list of content in a display. * Note that the contexts must be pre-loaded. */ function theme_panels_common_content_list($display) { $layout = panels_get_layout($display->layout); $content = '
'; foreach (panels_get_panels($layout, $display) as $panel_id => $title) { $content .= "
$title
"; if (!empty($display->panels[$panel_id])) { $content .= '
    '; foreach ($display->panels[$panel_id] as $pid) { $content .= '
  1. ' . panels_get_pane_title($display->content[$pid], $display->context) . '
  2. '; } $content .= '
'; } else { $content .= t('Empty'); } $content .= '
'; } $content .= '
'; return $content; } /** * Create a visible list of all the contexts available on an object. * Assumes arguments, relationships and context objects. * * Contexts must be preloaded. */ function theme_panels_common_context_list($object) { $titles = array(); $output = ''; $count = 1; // First, make a list of arguments. Arguments are pretty simple. if (!empty($object->arguments)) { foreach ($object->arguments as $argument) { $output .= ''; $output .= '' . t('Argument @count', array('@count' => $count)) . ''; $output .= '' . check_plain($argument['identifier']) . ''; $output .= ''; $titles[panels_argument_context_id($argument)] = $argument['identifier']; $count++; } } $count = 1; // Then, make a nice list of contexts. if (!empty($object->contexts)) { foreach ($object->contexts as $context) { $output .= ''; $output .= '' . t('Context @count', array('@count' => $count)) . ''; $output .= '' . check_plain($context['identifier']) . ''; $output .= ''; $titles[panels_context_context_id($context)] = $context['identifier']; $count++; } } // And relationships if (!empty($object->relationships)) { foreach ($object->relationships as $relationship) { $output .= ''; $output .= '' . t('From @title', array('@title' => $titles[$relationship['context']])) . ''; $output .= '' . check_plain($relationship['identifier']) . ''; $output .= ''; $titles[panels_relationship_context_id($relationship)] = $relationship['identifier']; $count++; } } if ($output) { return "$output
\n"; } }