You are here

vertical_tabs.module in Vertical Tabs 6

Provides vertical tabs capability for fieldsets in forms.

File

vertical_tabs.module
View source
<?php

/**
 * @file
 * Provides vertical tabs capability for fieldsets in forms.
 */

/**
 * Implements hook_menu().
 */
function vertical_tabs_menu() {
  $items['admin/settings/vertical-tabs'] = array(
    'title' => 'Vertical Tabs',
    'description' => 'Configure settings for vertical tabs.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'vertical_tabs_settings_form',
    ),
    'access arguments' => array(
      'administer site configuration',
    ),
    'file' => 'vertical_tabs.admin.inc',
  );
  return $items;
}

/**
 * Implements hook_theme().
 */
function vertical_tabs_theme() {
  return array(
    'vertical_tabs' => array(
      'arguments' => array(
        'element' => NULL,
      ),
    ),
  );
}

/**
 * Implements hook_form_alter().
 */
function vertical_tabs_form_alter(&$form, $form_state, $form_id) {

  // Add the support and default groupings for core forms.
  vertical_tabs_add_core_support($form, $form_id);
  $config = vertical_tabs_get_config($form_id);

  // Skip programmed or excluded forms.
  if (!empty($form['#programmed']) || $config === FALSE) {
    vertical_tabs_remove_vertical_tabs($form);
  }
  elseif ($config) {

    // Merge in the vertical tabs settings in case they already existed.
    $form += array(
      '#vertical_tabs' => array(),
    );
    if (is_array($config)) {
      $form['#vertical_tabs'] += $config;
    }
    $form['#pre_render'][] = 'vertical_tabs_form_pre_render';
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function vertical_tabs_form_node_type_form_alter(&$form, $form_state) {
  if (empty($form['#programmed']) && $form['#node_type']->type && variable_get('vertical_tabs_node_type_settings', 0)) {
    module_load_include('inc', 'vertical_tabs', 'vertical_tabs.admin');
    vertical_tabs_add_node_type_options($form, $form['#node_type']->type);
  }
}

/**
 * Add core module fieldset support.
 *
 * @param $form
 *   The form array, passed by reference.
 * @param $fomr_id
 *   The ID of the form.
 */
function vertical_tabs_add_core_support(&$form, $form_id) {
  $fieldsets = array();
  $group = '';
  if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] . '_node_form' == $form_id) {
    $fieldsets['revision_information'] = 'node';
    $fieldsets['author'] = 'node';
    $fieldsets['options'] = 'node';
    $fieldsets['book'] = 'book';
    $fieldsets['menu'] = 'menu';
    $fieldsets['comment_settings'] = 'comment';
    $fieldsets['attachments'] = 'upload';
    $fieldsets['path'] = 'path';
    $fieldsets['taxonomy'] = 'taxonomy';
    $group = 'additional_settings';
  }
  elseif ($form_id == 'node_type_form') {
    $fieldsets['submission'] = 'content_types';
    $fieldsets['workflow'] = 'content_types';
    $fieldsets['comment'] = 'comment';
    $group = 'additional_settings';
  }
  elseif ($form_id == 'block_admin_configure' || strpos($form_id, 'block_add_block_form') !== FALSE) {
    $fieldsets['user_vis_settings'] = 'block';
    $fieldsets['role_vis_settings'] = 'block';
    $fieldsets['page_vis_settings'] = 'block';
    $group = 'visibility_settings';
  }
  foreach ($fieldsets as $key => $module) {
    if (isset($form[$key])) {
      $form[$key] += array(
        '#group' => $group,
        '#attached' => array(),
      );
      $file = drupal_get_path('module', 'vertical_tabs') . '/core/' . $module . '.js';
      if (is_file($file)) {
        $form[$key]['#attached'] += array(
          'js' => array(),
        );
        $form[$key]['#attached']['js'] += array(
          'vertical-tabs' => $file,
        );
      }
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Add our color-handling submit handler to the color settings form.
 */
function vertical_tabs_form_system_theme_settings_alter(&$form, $form_state) {

  // Add our color-handling submit handler to the color settings form.
  if (isset($form['color']) && function_exists('gd_info')) {
    $form['#submit'][] = 'vertical_tabs_system_theme_settings_submit';
  }
}

/**
 * Submit handler for the theme settings page.
 */
function vertical_tabs_system_theme_settings_submit($form, &$form_state) {
  $theme = $form_state['values']['theme'];
  $info = $form_state['values']['info'];

  // Resolve palette
  $palette = $form_state['values']['palette'];
  if ($form_state['values']['scheme'] != '') {
    $scheme = explode(',', $form_state['values']['scheme']);
    foreach ($palette as $k => $color) {
      $palette[$k] = array_shift($scheme);
    }
  }
  vertical_tabs_generate_stylesheet($theme, $info, $palette);
}

/**
 * Color module support for Garland and Vertical Tabs.
 *
 * Most of this function is direct copy/paste from color_scheme_form_submit().
 */
function vertical_tabs_generate_stylesheet($theme, $info, $palette) {

  // Current CSS files.
  $css = variable_get('color_' . $theme . '_stylesheets', array());
  $files = variable_get('color_' . $theme . '_files', array());

  // Template file.
  $file = 'vertical_tabs.garland.css';

  // Prepare target locations for generated files.
  $paths['color'] = file_directory_path() . '/color';
  $paths['source'] = drupal_get_path('module', 'vertical_tabs') . '/garland/';
  $paths['files'] = $paths['map'] = array();
  if (count($css)) {
    $paths['id'] = preg_replace('/^.*?(' . $theme . '-[a-zA-Z0-9]+).*?$/', '$1', $css[0]);
    $paths['target'] = $paths['color'] . '/' . $paths['id'] . '/';
    $style = drupal_load_stylesheet($paths['source'] . $file, FALSE);

    // Rewrite stylesheet with new colors.
    $style = _color_rewrite_stylesheet($theme, $info, $paths, $palette, $style);
    $base_file = basename($file);
    $css[] = $paths['target'] . $base_file;
    $files[] = $paths['target'] . $base_file;
    _color_save_stylesheet($paths['target'] . $base_file, $style, $paths);

    // Update the list of files.
    variable_set('color_' . $theme . '_stylesheets', $css);
    variable_set('color_' . $theme . '_files', $files);
  }
}

/**
 * Implements hook_node_type().
 */
function vertical_tabs_node_type($op, $info) {
  if ($op == 'update' && !empty($info->old_type) && $info->old_type != $info->type) {
    vertical_tabs_rename_config($info->type . '_node_form', $info->old_type . '_node_form');
  }
  elseif ($op == 'delete') {
    vertical_tabs_delete_config($info->type . '_node_form');
  }
}

/**
 * Implements hook_fieldgroup_form().
 *
 * Apply group value to CCK fieldsets with the 'vertical tab' form display.
 */
function vertical_tabs_fieldgroup_form(&$form, $form_state, $form_id, $group) {
  if (in_array($group['settings']['form']['style'], array(
    'fieldset_vertical_tab',
  ))) {
    $form[$group['group_name']]['#group'] = 'additional_settings';
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Adds a 'vertical tab' form option on CCK fieldset settings.
 */
function vertical_tabs_form_fieldgroup_group_edit_form_alter(&$form, $form_state) {
  $form['settings']['form']['style']['#options']['fieldset_vertical_tab'] = t('vertical tab');
}
function vertical_tabs_get_config($form_id = NULL) {
  static $config;
  if (!isset($config)) {
    $config = array();
    $config += variable_get('vertical_tabs_forms', array());
    $config += vertical_tabs_get_default_config();
  }
  if (isset($form_id)) {
    return isset($config[$form_id]) ? $config[$form_id] : NULL;
  }
  else {
    return $config;
  }
}

/**
 * Get the default supported forms.
 */
function vertical_tabs_get_default_config() {
  $forms = array();
  $node_types = array_keys(node_get_types('names'));
  foreach ($node_types as $node_type) {
    $forms[$node_type . '_node_form'] = TRUE;
  }
  $forms['node_type_form'] = TRUE;
  $forms['block_admin_configure'] = TRUE;
  $forms['block_add_block_form'] = TRUE;
  return $forms;
}
function vertical_tabs_save_config($form_id, $fieldsets) {
  $config = variable_get('vertical_tabs_forms', array());
  $config[$form_id] = $fieldsets;
  variable_set('vertical_tabs_forms', $config);
}
function vertical_tabs_rename_config($old_form_id, $new_form_id) {
  $config = variable_get('vertical_tabs_forms', array());
  if (isset($config[$form_id])) {
    $config[$new_form_id] = $config[$old_form_id];
    unset($config[$old_form_id]);
    variable_set('vertical_tabs_forms', $config);
  }
}
function vertical_tabs_delete_config($form_id) {
  $config = variable_get('vertical_tabs_forms', array());
  unset($config[$form_id]);
  variable_set('vertical_tabs_forms', $config);
}

/**
 * Get all the fieldset elements from a form.
 */
function vertical_tabs_get_form_elements(&$form) {
  $elements = array();
  foreach (element_children($form) as $key) {
    if (!isset($form[$key]['#type'])) {

      // Ignore non-type elements.
      continue;
    }
    elseif (!in_array($form[$key]['#type'], array(
      'fieldset',
    ))) {

      // Ignore non-fieldset elements.
      continue;
    }
    elseif (isset($form[$key]['#access']) && !$form[$key]['#access']) {

      // Ignore elements the user cannot access.
      continue;
    }
    $elements[$key] =& $form[$key];
  }
  return $elements;
}

/**
 * Form pre-render callback; add vertical tabs to the form.
 */
function vertical_tabs_form_pre_render($form) {
  if (!isset($form['#vertical_tabs']) || !is_array($form['#vertical_tabs'])) {
    $form['#vertical_tabs'] = array();
  }
  vertical_tabs_add_vertical_tabs($form, $form['#vertical_tabs']);
  return $form;
}

/**
 * Add a vertical tab form element to a form.
 *
 * @param $form
 *   A form array to be altered.
 * @param $config
 *   An array of fieldsets to use in the vertical tabs. If no array is provided,
 *   all the fieldsets in the $form array will be used.
 * @return
 *   TRUE if the vertical tabs were added to the form, otherwise FALSE.
 */
function vertical_tabs_add_vertical_tabs(&$form, $config = array()) {
  global $theme;
  $settings = array();
  $weight = $delta = 0;

  // Iterate through the form's fieldset elements.
  $elements = vertical_tabs_get_form_elements($form);
  foreach (array_keys($elements) as $key) {
    $element =& $elements[$key];
    $element += array(
      '#group' => variable_get('vertical_tabs_default', 1),
    );

    // If there is a specific config set, override the default group setting.
    if (isset($config[$key]) && (bool) $config[$key] != (bool) $element['#group']) {
      $element['#group'] = $config[$key];
    }

    // Skip any non-grouped elements.
    if (empty($element['#group'])) {
      continue;
    }

    // Process the element.
    vertical_tabs_process_element($element, $key);
    vertical_tabs_process_attached($element);
    $settings[$key] = array(
      'name' => $element['#title'],
      'weight' => isset($element['#weight']) ? $element['#weight'] : 0,
      'callback' => isset($element['#summary_callback']) ? $element['#summary_callback'] : $key,
      'args' => isset($element['#summary_arguments']) ? $element['#summary_arguments'] : array(),
    );

    // Track the maximum weight for the vertical tabs element.
    $weight = max($weight, $settings[$key]['weight']);
    $settings[$key]['weight'] += 0.001 * $delta++;
  }

  // The JavaScript and CSS specific for this form.
  if (count($settings) >= variable_get('vertical_tabs_minimum', 1)) {
    $js = $css = array();

    // Add theme-specific CSS.
    if (isset($theme)) {
      $theme_stylesheets = variable_get('color_' . $theme . '_stylesheets', array());
      if (!$theme_stylesheets || !module_exists('color')) {

        // The theme-specific CSS will be only included by drupal_get_css() if
        // it exists so we do not need to check file_exists() here.
        $css[] = drupal_get_path('module', 'vertical_tabs') . '/' . $theme . '/vertical_tabs.' . $theme . '.css';
      }
      else {
        foreach ($theme_stylesheets as $path) {
          if (strpos($path, 'vertical_tabs.' . $theme . '.css') !== FALSE) {
            $css[] = $path;
          }
        }
      }

      // Ensure the CSS files actually exist.
      $css = array_filter($css, 'file_exists');
    }

    // User sort orders by the "weight" key.
    uasort($settings, '_user_sort');
    $form['vertical_tabs'] = array(
      '#type' => 'markup',
      '#value' => '',
      '#theme' => 'vertical_tabs',
      '#attributes' => array(
        'class' => 'vertical-tabs clear-block',
      ),
      '#weight' => $weight,
      '#attached' => array(
        'js' => $js,
        'css' => $css,
      ),
    );
    $form['vertical_tabs']['#attached']['js'][] = array(
      'data' => array(
        'verticalTabs' => $settings,
      ),
      'type' => 'setting',
    );

    // Resort the form since we've added a new element after it's been sorted.
    uasort($form, 'element_sort');
    return TRUE;
  }
}

/**
 * Process an element for vertical tabs.
 */
function vertical_tabs_process_element(&$element, $key) {

  // Merge defaults.
  $element += array(
    '#attributes' => array(),
  );
  $element['#attributes'] += array(
    'class' => '',
  );

  // Add a class to identify the fieldset.
  $element['#attributes']['class'] .= ' vertical-tabs-fieldset vertical-tabs-' . $key;
  return $element;
}
function vertical_tabs_process_attached($element) {
  $element += array(
    '#attached' => array(),
  );
  $element['#attached'] += array(
    'js' => array(),
    'css' => array(),
  );

  // Add any attached vertical tabs JavaScript.
  // Copied from form_process_attached() in Drupal 7.
  foreach (array(
    'js',
    'css',
  ) as $type) {
    foreach ($element['#attached'][$type] as $data => $options) {

      // If the value is not an array, it's a filename and passed as first
      // (and only) argument.
      if (!is_array($options)) {
        $data = $options;
        $options = array();
      }

      // In some cases, the first parameter ($data) is an array. Arrays can't be
      // passed as keys in PHP, so we have to get $data from the value array.
      if (is_numeric($data)) {
        $data = $options['data'];
        unset($options['data']);
      }
      $options += array(
        'type' => 'module',
      );
      if ($type == 'js') {
        drupal_add_js($data, $options['type']);
      }
      else {
        drupal_add_css($data, $options['type']);
      }
    }
  }
}

/**
 * Remove vertical tabs elements and processing from a form.
 */
function vertical_tabs_remove_vertical_tabs(&$form) {
  unset($form['#vertical_tabs']);
  if (isset($form['vertical_tabs']['#vertical_tabs_settings'])) {
    unset($form['vertical_tabs']);
  }
  if (isset($form['#pre_render'])) {
    $form['#pre_render'] = array_diff($form['#pre_render'], array(
      'vertical_tabs_form_pre_render',
    ));
  }
}

/**
 * After build function to add vertical tabs JS and CSS to the form.
 */
function theme_vertical_tabs($element) {
  static $added = FALSE;
  if (!$added) {
    drupal_add_js(drupal_get_path('module', 'vertical_tabs') . '/vertical_tabs.js');
    drupal_add_css(drupal_get_path('module', 'vertical_tabs') . '/vertical_tabs.css');
    $added = TRUE;
  }
  vertical_tabs_process_attached($element);
  return '<div class="' . $element['#attributes']['class'] . '">&nbsp;</div>';
}

/**
 * Implements hook_form_controller_info().
 */
function vertical_tabs_form_info() {
  $alterations['vertical_tabs_form'] = array(
    'title' => t('Vertical tabs'),
    'description' => t('Enables fieldsets to be collapsed into a vertical tab display.'),
    'form callback' => 'vertical_tabs_form_configure',
  );
  return $alterations;
}
function vertical_tabs_form_configure(&$complete_form, $form_id, $context) {
  if ($elements = vertical_tabs_get_form_elements($context['form'])) {

    // Fetch the configuration.
    $config = vertical_tabs_get_config($form_id);

    // Check if this form is currently vertical tabified.
    $is_form_tabified = isset($context['form']['vertical_tabs']) || isset($context['form']['#pre_render']) && in_array('vertical_tabs_form_pre_render', $context['form']['#pre_render']);
    $form['status'] = array(
      '#type' => 'checkbox',
      '#title' => t('Vertical tabify this form.'),
      '#default_value' => isset($config) ? $config !== FALSE : $is_form_tabified,
    );

    // Merge default values and correct non-key-matching values.
    // @todo Keep settings for non-accessible fieldsets set by more priviledged users?
    $defaults = is_array($config) ? $config : array();
    $options = array();
    foreach ($elements as $key => $element) {
      $options[$key] = $element['#title'];
      if (!isset($defaults[$key]) && !empty($element['#group'])) {
        $defaults[$key] = $key;
      }
    }
    $form['fieldsets'] = array(
      '#type' => 'checkboxes',
      '#title' => t('Include the following elements in the vertical tabs'),
      '#options' => $options,
      '#default_value' => $defaults,
    );
    if (module_exists('ctools')) {
      ctools_include('dependent');
      $form['fieldsets'] += array(
        '#process' => array(
          'expand_checkboxes',
          'ctools_dependent_process',
        ),
        '#dependency' => array(
          'edit-vertical-tabs-form-status' => array(
            TRUE,
          ),
        ),
        '#prefix' => '<div><div id="edit-vertical-tabs-form-fieldsets-wrapper">',
        '#suffix' => '</div></div>',
      );
    }
    $complete_form['#submit'][] = 'vertical_tabs_form_configure_submit';
    return $form;
  }
}
function vertical_tabs_form_configure_submit($form, &$form_state) {
  $form_id = $form_state['form']['form_id'];
  if ($form_state['values']['vertical_tabs_form']['status']) {
    vertical_tabs_save_config($form_id, $form_state['values']['vertical_tabs_form']['fieldsets']);
  }
  else {
    vertical_tabs_save_config($form_id, FALSE);
  }
}

Functions

Namesort descending Description
theme_vertical_tabs After build function to add vertical tabs JS and CSS to the form.
vertical_tabs_add_core_support Add core module fieldset support.
vertical_tabs_add_vertical_tabs Add a vertical tab form element to a form.
vertical_tabs_delete_config
vertical_tabs_fieldgroup_form Implements hook_fieldgroup_form().
vertical_tabs_form_alter Implements hook_form_alter().
vertical_tabs_form_configure
vertical_tabs_form_configure_submit
vertical_tabs_form_fieldgroup_group_edit_form_alter Implements hook_form_FORM_ID_alter().
vertical_tabs_form_info Implements hook_form_controller_info().
vertical_tabs_form_node_type_form_alter Implements hook_form_FORM_ID_alter().
vertical_tabs_form_pre_render Form pre-render callback; add vertical tabs to the form.
vertical_tabs_form_system_theme_settings_alter Implements hook_form_FORM_ID_alter().
vertical_tabs_generate_stylesheet Color module support for Garland and Vertical Tabs.
vertical_tabs_get_config
vertical_tabs_get_default_config Get the default supported forms.
vertical_tabs_get_form_elements Get all the fieldset elements from a form.
vertical_tabs_menu Implements hook_menu().
vertical_tabs_node_type Implements hook_node_type().
vertical_tabs_process_attached
vertical_tabs_process_element Process an element for vertical tabs.
vertical_tabs_remove_vertical_tabs Remove vertical tabs elements and processing from a form.
vertical_tabs_rename_config
vertical_tabs_save_config
vertical_tabs_system_theme_settings_submit Submit handler for the theme settings page.
vertical_tabs_theme Implements hook_theme().