You are here

webform_addmore.module in Webform Add More 7.2

Same filename and directory in other branches
  1. 6 webform_addmore.module
  2. 7 webform_addmore.module

Hide/Show Webform items in fieldsets using add/remove buttons.

File

webform_addmore.module
View source
<?php

/**
 * @file
 * Hide/Show Webform items in fieldsets using add/remove buttons.
 */

/**
 * Implements hook_FORM_ID_form_alter().
 */
function webform_addmore_form_webform_component_edit_form_alter(&$form, &$form_state) {
  if ($form_state['build_info']['args'][1]['type'] !== 'fieldset') {
    return;
  }
  $addmore = array(
    '#type' => 'fieldset',
    '#collapsible' => TRUE,
    '#collapsed' => empty($form_state['build_info']['args'][1]['extra']['webform_addmore']),
    '#title' => t('Add more'),
  );
  $addmore['addmore'] = array(
    '#type' => 'checkbox',
    '#title' => t('Wrap children elements into a repeatable "Add more" behaviour'),
    '#default_value' => !empty($form_state['build_info']['args'][1]['extra']['webform_addmore']['addmore']) ? 1 : 0,
  );
  $addmore['addmore_add'] = array(
    '#type' => 'textfield',
    '#title' => t('Add more text'),
    '#default_value' => !empty($form_state['build_info']['args'][1]['extra']['webform_addmore']['addmore_add']) ? $form_state['build_info']['args'][1]['extra']['webform_addmore']['addmore_add'] : t('Add one'),
  );

  // Remove text can be blank.
  $remove = t('Remove one');
  if (!empty($form_state['build_info']['args'][1]['extra']['webform_addmore']['addmore_remove'])) {
    $remove = $form_state['build_info']['args'][1]['extra']['webform_addmore']['addmore_remove'];
  }
  else {
    if (!empty($form_state['build_info']['args'][1]['extra']['webform_addmore']['addmore_add'])) {
      $remove = '';
    }
  }
  $addmore['addmore_remove'] = array(
    '#type' => 'textfield',
    '#title' => t('Remove text'),
    '#default_value' => $remove,
    '#description' => t('Leave blank to have no "Remove" button'),
  );
  $addmore['addmore_show'] = array(
    '#type' => 'textfield',
    '#title' => t('Number of children to display'),
    '#default_value' => !empty($form_state['build_info']['args'][1]['extra']['webform_addmore']['addmore_show']) ? $form_state['build_info']['args'][1]['extra']['webform_addmore']['addmore_show'] : 1,
    '#description' => t('The number of children items that will be initially displayed'),
    '#element_validate' => array(
      'element_validate_integer',
    ),
  );
  $form['extra']['webform_addmore'] = $addmore;
}

/**
 * Implements hook_webform_component_render_alter().
 */
function webform_addmore_webform_component_render_alter(&$element, &$component) {
  if (!empty($component['extra']['webform_addmore']['addmore'])) {

    // Mark the fact our form uses addmore.
    _webform_addmore_webform_uses_addmore_set($component['nid']);

    // Because _webform_client_form_add_component is recursive,
    // we should be able to alter of children from here.
    foreach ($component['children'] as $cid => $child) {
      $component['children'][$cid]['#webform_addmore']['pid'] = $component['cid'];
    }
    $element['#webform_addmore']['cid'] = $component['cid'];
  }

  // Alter children themselves.
  if (!empty($component['#webform_addmore']['pid'])) {
    $element['#webform_addmore']['pid'] = $component['#webform_addmore']['pid'];
  }
}

/**
 * Static setter for webform forms where addform is in use.
 * @param int $nid a webform node nid.
 */
function _webform_addmore_webform_uses_addmore_set($nid) {
  $nids =& drupal_static('_webform_addmore_webform_uses_addmore');
  $nids[$nid] = $nid;
}

/**
 * Static getter for webform forms where addform is in use.
 * @param int $nid a webform node nid.
 * @return int Either the $nid given as argument if found or 0 if not.
 */
function _webform_addmore_webform_uses_addmore_get($nid) {
  $nids =& drupal_static('_webform_addmore_webform_uses_addmore');
  return !empty($nids[$nid]) ? $nids[$nid] : 0;
}

/**
 * Implements hook_form_webform_client_form_alter().
 */
function webform_addmore_form_webform_client_form_alter(&$form, &$form_state, $form_id) {
  $node = $form['#node'];
  if (_webform_addmore_webform_uses_addmore_get($node->nid)) {
    _webform_addmore_client_form_ajaxify($form['submitted'], $form_state);
    $form['#validate'][] = 'webform_addmore_form_webform_client_form_validate';
  }
}

/**
 * Helper function. Recursively traverse a form element,
 * rendering or not children based on the form state.
 * @param array $element of the form to proceed.
 * @param array $form_state of current form.
 */
function _webform_addmore_client_form_ajaxify(&$element, &$form_state) {

  // Rely on marker set earlier.
  if (!empty($element['#webform_addmore']['cid'])) {
    $cid = $element['#webform_addmore']['cid'];
    if (empty($form_state['#webform_addmore'][$cid])) {
      $form_state['#webform_addmore'][$cid] = 1;
    }
    if (!empty($form_state['triggering_element']['#name'])) {
      if ($form_state['triggering_element']['#name'] === 'webformaddmore_add_' . $cid) {
        $form_state['#webform_addmore'][$cid]++;
      }
      else {
        if ($form_state['triggering_element']['#name'] === 'webformaddmore_remove_' . $cid) {
          $form_state['#webform_addmore'][$cid]--;
        }
      }
    }
    $i = 0;
    $max = count(element_children($element));

    // Process children element, unsetting the ones
    // to hide.
    foreach (element_children($element) as $key) {
      if ($i < $form_state['#webform_addmore'][$cid]) {
        _webform_addmore_client_form_ajaxify($element[$key], $form_state);
        $i++;
      }
      else {

        // We can't just 'unset' these, as some other modules
        // like clientside_validation expect them.
        $element[$key]['#access'] = FALSE;
        _webform_addmore_element_unrequire($element[$key]);
      }
    }

    // Generate add and remove buttons.
    $ops = array();
    if ($i < $max) {
      $ops[] = 'add';
    }
    if ($i > 1 && !empty($element['#webform_component']['extra']['webform_addmore']['addmore_remove'])) {
      $ops[] = 'remove';
    }
    _webform_addmore_element_add_buttons($element, $ops);
    $element['#attributes']['id'] = 'webform-addmore-' . $cid;
  }
  else {
    if (!empty($element)) {
      foreach (element_children($element) as $key) {
        _webform_addmore_client_form_ajaxify($element[$key], $form_state);
      }
    }
  }
}

/**
 * Helper function. Sets the #required property of an element
 * and its children to FALSE.
 * @param array $element of a webform.
 */
function _webform_addmore_element_unrequire(&$element) {
  $element['#required'] = FALSE;
  foreach (element_children($element) as $key) {
    _webform_addmore_element_unrequire($element[$key]);
  }
}

/**
 * Helper function. Recursively remove the
 * add more element from $form_state values.
 * @param array $values of a webform submission.
 */
function _webform_addmore_element_clean_values(&$values) {
  if (empty($values) || !is_array($values)) {
    return;
  }
  foreach (element_children($values) as $key) {
    if ($key === 'webform_addmore') {
      unset($values[$key]);
    }
    else {
      _webform_addmore_element_clean_values($values[$key]);
    }
  }
}

/**
 * Helper function. Builds the 'Add' and 'Remove' buttons.
 * @param array $element to modify.
 * @param array $ops to add to the form ('add', 'remove' or both values).
 */
function _webform_addmore_element_add_buttons(&$element, $ops) {
  $element['webform_addmore'] = array(
    '#type' => 'container',
    '#attributes' => array(
      'class' => array(
        'container-inline',
      ),
    ),
    '#weight' => 255,
  );
  foreach ($ops as $op) {
    $element['webform_addmore']['webform_addmore_' . $op] = array(
      '#type' => 'button',
      '#value' => check_plain($element['#webform_component']['extra']['webform_addmore']['addmore_' . $op]),
      '#name' => 'webformaddmore_' . $op . '_' . $element['#webform_component']['cid'],
      '#limit_validation_errors' => array(),
      '#ajax' => array(
        'callback' => 'webform_addmore_form_webform_client_form_ajax',
        'wrapper' => 'webform-addmore-' . $element['#webform_component']['cid'],
      ),
    );
  }

  // Let other modules alter this.
  drupal_alter('webform_addmore_buttons', $element);
}

/**
 * Ajax callback for Add/Remove buttons.
 */
function webform_addmore_form_webform_client_form_ajax($form, $form_state) {
  if (!empty($form_state['triggering_element']['#name']) && strpos($form_state['triggering_element']['#name'], 'webformaddmore') === 0) {

    // Iterate parents array to return the relevant part.
    $return = $form;
    foreach ($form_state['triggering_element']['#array_parents'] as $field) {
      if ($field === 'webform_addmore') {
        return $return;
      }
      $return = $return[$field];
    }
  }
}
function webform_addmore_form_webform_client_form_validate(&$form, &$form_state) {
  _webform_addmore_element_clean_values($form_state['values']['submitted']);
}

Functions

Namesort descending Description
webform_addmore_form_webform_client_form_ajax Ajax callback for Add/Remove buttons.
webform_addmore_form_webform_client_form_alter Implements hook_form_webform_client_form_alter().
webform_addmore_form_webform_client_form_validate
webform_addmore_form_webform_component_edit_form_alter Implements hook_FORM_ID_form_alter().
webform_addmore_webform_component_render_alter Implements hook_webform_component_render_alter().
_webform_addmore_client_form_ajaxify Helper function. Recursively traverse a form element, rendering or not children based on the form state.
_webform_addmore_element_add_buttons Helper function. Builds the 'Add' and 'Remove' buttons.
_webform_addmore_element_clean_values Helper function. Recursively remove the add more element from $form_state values.
_webform_addmore_element_unrequire Helper function. Sets the #required property of an element and its children to FALSE.
_webform_addmore_webform_uses_addmore_get Static getter for webform forms where addform is in use.
_webform_addmore_webform_uses_addmore_set Static setter for webform forms where addform is in use.