You are here

formfilter.module in Formfilter 5

Same filename and directory in other branches
  1. 7 formfilter.module

File

formfilter.module
View source
<?php

/**
 * Implementation of hook_menu().
 */
function formfilter_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'path' => 'admin/settings/formfilter',
      'title' => t('Form Filter'),
      'description' => t('Select what filtering to apply.'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'formfilter_admin_settings',
      ),
      'access' => user_access('administer site configuration'),
    );
  }
  return $items;
}

/**
 * Implementation of hook_perm().
 */
function formfilter_perm() {
  return array(
    'administer form filters',
    'view forms without filtering',
  );
}

/**
 * Menu callback for module settings.
 */
function formfilter_admin_settings() {
  $form = array();
  $form['formfilter_ui'] = array(
    '#type' => 'checkbox',
    '#title' => t('Filtering UI'),
    '#description' => t('Check this option to provide a link, <em>Filter this form</em> at the bottom of every form (for users with the <em>administer form filters</em> permission). Clicking the link will bring up a version of the form with checkboxes for filtering (hiding) unwanted elements.'),
    '#default_value' => variable_get('formfilter_ui', 1),
  );
  $form['formfilter_simplify_node'] = array(
    '#type' => 'radios',
    '#title' => t('Simplify node form'),
    '#default_value' => variable_get('formfilter_simplify_node', 0),
    '#options' => array(
      t('Disabled'),
      t('Enabled'),
    ),
    '#description' => t('Simplify the node form by pulling the <em>Promote</em> and <em>Sticky</em> options out of fieldsets and then putting all the fieldsets in one <em>Advanced options</em> fieldset.'),
  );
  return system_settings_form($form);
}

/**
 * Implementation of hook_form_alter().
 *
 * Add all users to select for assigning issues.
 */
function formfilter_form_alter($form_id, &$form) {
  global $user;
  $filters = variable_get('formfilter', array());

  // If user has access to create form filters, add filtering link or filtering
  // checkboxes.
  if (variable_get('formfilter_ui', 1) && user_access('administer form filters')) {

    // Comment form doesn't have a submit button and so can't be filtered
    // if preview is required.
    if ($form_id == 'comment_form' && variable_get('comment_preview', COMMENT_PREVIEW_REQUIRED) == COMMENT_PREVIEW_REQUIRED) {
      return;
    }
    if ($form_id == $_REQUEST['formfilter_id']) {
      $form['formfilter'] = array(
        '#type' => 'tree',
      );
      _formfilter_add_selectors($form, array_key_exists($form_id, $filters) ? $filters[$form_id] : NULL);
      $form['#formfilter_id'] = $form_id;
      $form['#validate']['formfilter_form_validate'] = array();
    }
    else {
      $form['#suffix'] .= '<div>' . l(t('Filter this form'), $_GET['q'], array(), 'formfilter_id=' . $form_id) . '</div>';

      // If the user applying a filter had permission to view forms without filtering,
      // give her or him a link to preview the filtering if a filter exists on the form.
      if (array_key_exists($form_id, $filters) && user_access('view forms without filtering') && !$_REQUEST['formfilter_preview']) {
        $form['#suffix'] .= '<div>' . l(t('Preview a filtered version of this form'), $_GET['q'], array(), 'formfilter_preview=1') . '</div>';
      }
    }
  }
  if (!$_REQUEST['formfilter_id'] && array_key_exists($form_id, $filters) && (!user_access('view forms without filtering') || $_REQUEST['formfilter_preview'])) {
    $form_filters = array();

    // Convert filters to arrays.
    foreach (array_keys($filters[$form_id]) as $filter) {
      $form_filters[] = explode('|', $filter);
    }
    if ($_REQUEST['formfilter_preview']) {
      drupal_set_message(t('Previewing filtered version of form.'));
    }
    formfilter_filter_form($form, $form_filters);
  }

  // Simplify the node form.
  if (variable_get('formfilter_simplify_node', 0) && isset($form['type']) && $form['type']['#value'] . '_node_form' == $form_id) {

    // Remove the most-used fields from the form admin fieldsets. Add them
    // below the body.
    if ($form['body_filter']) {

      // Move 'promote' and 'sticky'.
      if ($form['options']) {
        foreach (array(
          'promote',
          'sticky',
        ) as $key) {
          if ($form['options'][$key]) {
            $form['body_filter'][$key] = $form['options'][$key];
            unset($form['options'][$key]);
          }
        }
      }
    }

    // Simplify the node form.
    // Create an 'advanced' fieldset...
    $form['advanced'] = array(
      '#type' => 'fieldset',
      '#title' => t('Advanced options'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
    );

    // ...and move all first-level fieldsets there.
    foreach (element_children($form) as $key) {
      if (!in_array($key, array(
        'advanced',
        'taxonomy',
      )) && $form[$key]['#type'] && $form[$key]['#type'] == 'fieldset') {
        $form['advanced'][$key] = $form[$key];
        unset($form[$key]);
      }
    }

    // If nothing has been moved to the advanced fieldset, drop it.
    if (!count(element_children($form['advanced']))) {
      unset($form['advanced']);
    }
  }
}

/**
 * Validate a form filtering submission. Read in data from the $_POST because
 * we have added elements not via the Forms API.
 */
function formfilter_form_validate($form_id, $form_values, $form) {
  $filters = variable_get('formfilter', array());
  $filters[$form_id] = array_filter($_REQUEST['edit']['formfilter']);
  variable_set('formfilter', $filters);
  drupal_set_message(t('Form filtering registered.'));
  drupal_goto($_GET['q']);
}

/**
 * Add selectors to a form for the user to select which elements to filter.
 */
function _formfilter_add_selectors(&$form, $filters = NULL, $keys = array()) {
  foreach (element_children($form) as $key) {
    $keys[] = $key;

    // Prevent validation errors when form is submitted.
    unset($form[$key]['#required']);
    if (isset($form[$key]['#type']) && in_array($form[$key]['#type'], formfilter_supported_types())) {
      $form[$key]['#suffix'] .= '<div>' . t('Hide %title:', array(
        '%title' => isset($form[$key]['#title']) ? $form[$key]['#title'] : $key,
      )) . ' <input type="checkbox" name="edit[formfilter][' . implode('|', $keys) . ']" value="1"' . ($filters && $filters[implode('|', $keys)] ? ' checked="checked" ' : ' ') . '/></div>';
    }
    _formfilter_add_selectors($form[$key], $filters, $keys);
    unset($keys[array_search($key, $keys)]);
  }
}

/**
 * Array of form element types for which filtering is supported.
 */
function formfilter_supported_types() {
  return array(
    'button',
    'fieldset',
    'select',
    'textfield',
    'checkbox',
    'checkboxes',
    'radio',
    'radios',
    'textarea',
    'item',
    'file',
    'weight',
    'markup',
  );
}

/**
 * Filter a form so the requested elements are invisible (passed as values).
 *
 * @param $form
 *   A reference to the form to be altered.
 * @param $filters
 *   An array of elements to make invisibile in the form, each element in turn being
 *   an array of form keys corresponding to the path of the element in the form
 *   structure. For example, to hide the element $form['comment_filter']['format']
 *   from $form, you could call this function as follows:
 *   formfilter_filter_form($form, array(array('comment_filter', 'format')));
 * @param $inverse
 *   If TRUE, all elements excepts the ones given in $filters will become
 *   invisible. This defaults to FALSE.
 */
function formfilter_filter_form(&$form, $filters, $inverse = FALSE) {

  // Iterate through filters.
  $filtered = array();
  foreach ($filters as $filter) {
    _formfilter_filter_form($form, $filter, $inverse);
    $filtered[] = $filter[0];
  }
  if ($inverse) {
    foreach (element_children($form) as $key) {
      if (!in_array($key, $filtered)) {
        _formfilter_filter_element($form[$key]);
      }
    }
  }
}

/**
 * Apply filtering to a form.
 */
function _formfilter_filter_form(&$form, $filter, $inverse) {

  // Iterate through form elements.
  foreach (element_children($form) as $key) {

    // Determine if there are further levels of nesting.
    if ($filter[0] == $key) {

      // If not, send the element for filtering.
      if (count($filter) == 1) {
        if ($inverse) {
          continue;
        }
        else {
          _formfilter_filter_element($form[$key]);
        }
      }
      else {
        if ($inverse) {
          _formfilter_filter_element($form[$key], FALSE);
        }
        array_shift($filter);
        _formfilter_filter_form($form[$key], $filter, $inverse);
      }
      break;
    }
    elseif ($inverse) {
      _formfilter_filter_element($form[$key]);
    }
  }
}

/**
 * Filter a form element.
 */
function _formfilter_filter_element(&$element, $recurse = TRUE) {

  // Don't filter unsupported types. If no type is set, however, we do filter.
  if ($element['#type'] && !in_array($element['#type'], formfilter_supported_types())) {
    return;
  }

  // Read in values. Bail if filtering conditions not met.
  switch ($element['#type']) {
    case 'fieldset':
    case 'button':
    case 'item':
    case 'file':
    case 'markup':
      break;
    case 'select':
    case 'checkboxes':
    case 'radios':
      $value = isset($element['#default_value']) ? $element['#default_value'] : key($element['#options']);
      break;
    case 'weight':
      $value = isset($element['#default_value']) ? $element['#default_value'] : 0;
      break;
    case 'checkbox':
    case 'radio':

      // TBD: Why doesn't passing values work for checkbox elements?

      //$value = isset($element['#default_value']) ? $element['#default_value'] : $element['#return_value'];

      //break;

      // For now, pass them as hidden elements.
      $element['#type'] = 'hidden';
      $element['#value'] = isset($element['#default_value']) ? $element['#default_value'] : $element['#return_value'];
      return;
    case 'textfield':
    case 'textarea':
      $value = isset($element['#default_value']) ? $element['#default_value'] : NULL;
      if (!$value && $element['#required']) {
        return;
      }
      break;
  }

  // Unset unneeded keys. We don't simply redefine the arrays as they may have
  // nested form elements (element_children).
  foreach (element_properties($element) as $key) {
    switch ($key) {
      case '#tree':
        continue;
      default:
        unset($element[$key]);
    }
  }

  // Set final form of array.
  if ($value) {
    $element += array(
      '#type' => 'value',
      '#value' => $value,
    );
  }

  // Convert child elements.
  if ($recurse) {
    foreach (element_children($element) as $key) {
      _formfilter_filter_element($element[$key]);
    }
  }
}

Functions

Namesort descending Description
formfilter_admin_settings Menu callback for module settings.
formfilter_filter_form Filter a form so the requested elements are invisible (passed as values).
formfilter_form_alter Implementation of hook_form_alter().
formfilter_form_validate Validate a form filtering submission. Read in data from the $_POST because we have added elements not via the Forms API.
formfilter_menu Implementation of hook_menu().
formfilter_perm Implementation of hook_perm().
formfilter_supported_types Array of form element types for which filtering is supported.
_formfilter_add_selectors Add selectors to a form for the user to select which elements to filter.
_formfilter_filter_element Filter a form element.
_formfilter_filter_form Apply filtering to a form.