You are here

cck_select_other.module in CCK Select Other 6

Implements a select list widget that lets a user provide an alternate option.

File

cck_select_other.module
View source
<?php

/**
 * @file
 * Implements a select list widget that lets a user provide an alternate option.
 */

/**
 * Implementation of hook_widget_info().
 */
function cck_select_other_widget_info() {
  return array(
    'cck_select_other' => array(
      'label' => t('Select other list'),
      'field types' => array(
        'text',
        'number_integer',
        'number_decimal',
        'number_float',
      ),
      'multiple values' => CONTENT_HANDLE_MODULE,
      'callbacks' => array(
        'default value' => CONTENT_CALLBACK_DEFAULT,
      ),
    ),
  );
}

/**
 * Implementation of hook_widget_settings
 */
function cck_select_other_widget_settings($op, $widget) {
  switch ($op) {
    case 'form':
      $form['select_list_options'] = array(
        '#type' => 'textarea',
        '#title' => t('Select list options'),
        '#description' => t('CCK Select Other uses a separate text area to generate options. You may also put restricted values in the Allowed Values text area.'),
        '#default_value' => $widget['select_list_options'],
      );
      $form['select_list_options_fieldset']['advanced_options'] = array(
        '#type' => 'fieldset',
        '#title' => t('PHP code'),
        '#collapsible' => TRUE,
        '#collapsed' => empty($widget['select_list_options_php']),
      );
      if (user_access('Use PHP input for field settings (dangerous - grant with care)')) {
        $form['select_list_options_fieldset']['advanced_options']['select_list_options_php'] = array(
          '#type' => 'textarea',
          '#title' => t('Code'),
          '#default_value' => !empty($widget['select_list_options_php']) ? $widget['select_list_options_php'] : '',
          '#rows' => 6,
          '#description' => t('Advanced usage only: PHP code that returns a keyed array of proposed select list options. Should not include &lt;?php ?&gt; delimiters. If this field is filled out, the array returned by this code will override the proposed select list options above.'),
        );
      }
      else {
        $form['select_list_options_fieldset']['advanced_options']['markup_select_list_options_php'] = array(
          '#type' => 'item',
          '#title' => t('Code'),
          '#value' => !empty($widget['select_list_options_php']) ? '<code>' . check_plain($widget['select_list_options_php']) . '</code>' : t('&lt;none&gt;'),
          '#description' => empty($widget['select_list_options_php']) ? t("You're not allowed to input PHP code.") : t('This PHP code was set by an administrator and will override the allowed values list above.'),
        );
      }
      return $form;
      break;
    case 'save':
      return array(
        'select_list_options',
        'select_list_options_php',
      );
      break;
  }
}

/**
 * Implementation of hook_elements
 */
function cck_select_other_elements() {
  return array(
    'cck_select_other' => array(
      '#input' => TRUE,
      '#columns' => array(
        'value',
      ),
      '#delta' => 0,
      '#process' => array(
        'cck_select_other_process',
      ),
      '#pre_render' => array(
        'cck_select_other_pre_render',
      ),
      '#post_render' => array(
        'cck_select_other_post_render',
      ),
    ),
  );
}

/**
 * Implementation of hook_widget().
 */
function cck_select_other_widget(&$form, &$form_state, $field, $items, $delta = NULL) {
  $element = array(
    '#type' => $field['widget']['type'],
    '#default_value' => '',
  );
  $options = cck_select_other_options($field);
  if (empty($items)) {
    $items[] = array(
      'value' => '',
    );
  }
  if (!isset($options[$items[$delta]['value']])) {
    $def = 'other';
  }
  else {
    $def = $items[$delta]['value'];
  }
  $element['select_other_list'] = array(
    '#type' => 'select',
    '#title' => t(''),
    '#description' => t('Select other to enter your own option.'),
    '#options' => $options,
    '#default_value' => $def,
  );
  $element['select_other_text_input'] = array(
    '#type' => 'textfield',
    '#title' => t('Specify other'),
    '#default_value' => $def == 'other' ? check_plain($items[$delta]['value']) : '',
  );
  return $element;
}

/**
 * Process an individual element.
 *
 * Build the form element. When creating a form using FAPI #process,
 * note that $element['#value'] is already set.
 *
 * The $fields array is in $form['#field_info'][$element['#field_name']].
 */
function cck_select_other_process($element, $edit, &$form_state, $form) {
  $field_name = $element['#field_name'];
  $field = $form['#field_info'][$field_name];
  $delta = $element['#delta'];
  $field_key = $element['#columns'][0];
  $element['#type'] = 'fieldset';
  unset($element['#value']);

  //FIXME: still necessary? See new else block down below...
  $element['#collapsible'] = TRUE;
  $element['#collapsed'] = FALSE;
  if ($edit['select_other_list'] == 'other' && !empty($edit['select_other_text_input']) && !empty($edit)) {
    $element['#value'] = array(
      array(
        'value' => $edit['select_other_text_input'],
      ),
    );
    $form_state['values'][$field_name] = $element['#value'][$delta];
    $form_state['clicked_button']['#post'][$field_name] = $element['#value'][$delta];
  }
  elseif (!empty($edit)) {
    $element['#value'] = array(
      array(
        'value' => $edit['select_other_list'],
      ),
    );
    $form_state['values'][$field_name] = $element['#value'][$delta];
    $form_state['clicked_button']['#post'][$field_name] = $element['#value'][$delta];
  }
  else {
    $element['#value'] = '';
  }
  if (empty($element['#element_validate'])) {
    $element['#element_validate'] = array();
  }
  $form_state['#field_info'][$field['field_name']] = $field;
  if (!empty($edit)) {
    unset($element['select_other_list']);
    unset($element['select_other_text_input']);
  }
  return $element;
}

/**
 * Helper function for finding the options list for this field.
 */
function cck_select_other_options($field) {
  $options = eval($field['widget']['select_list_options_php']);
  if (empty($options)) {
    $options_str = $field['widget']['select_list_options'];
    if (!empty($options_str)) {
      $options_arr = preg_split("/[\r]?[\n]/", $options_str);
      if (count($options_arr) > 0) {
        foreach ($options_arr as $option_str) {
          $option_arr = preg_split("/\\|/", $option_str);
          if (count($option_arr) == 2) {
            $options[check_plain($option_arr[0])] = t('!option', array(
              '!option' => $option_arr[1],
            ));
          }
          else {
            $options[check_plain($option_arr[0])] = t('!option', array(
              '!option' => $option_arr[0],
            ));
          }
        }
      }
    }
  }
  else {
    foreach ($options as $key => $option) {
      if (!is_numeric($key)) {
        $key = check_plain($key);
      }
      $options[$key] = t('!option', array(
        '!option' => $option,
      ));
    }
  }
  if (!isset($options['other'])) {
    $options['other'] = t('Other');
  }
  return $options;
}

/**
 * Pre render callback for the form so we can recreate the fake form after it gets
 * blown away by the CCK process callback.
 * @param $form the form
 * @return $form
 */
function cck_select_other_pre_render($form) {
  static $js;
  if (isset($form['select_other_list'])) {
    return $form;
  }
  $field_name = substr($form['#field_name'], 6);
  if (!$js) {
    drupal_add_js(array(
      'CCKSelectOther' => array(
        'field' => $field_name,
      ),
    ), 'setting');
    drupal_add_js(drupal_get_path('module', 'cck_select_other') . '/cck_select_other.js');
    $js = TRUE;
  }
  else {
    drupal_add_js(array(
      'CCKSelectOther' => array(
        'field' => $field_name,
      ),
    ), 'setting');
  }
  unset($form['#default_value']);
  unset($form['#value']);
  $field = content_fields($form['#field_name']);
  $def = $form['#post'][$form['#field_name']]['select_other_text_input'];
  $select_def = $form['#post'][$form['#field_name']]['select_other_list'];
  $delta = $form['#delta'];
  $options = cck_select_other_options($field);
  $new_form = array(
    '#type' => 'fieldset',
    '#title' => t($field['widget']['label']),
    '#description' => $form['#description'],
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
    '#delta' => $form['#delta'],
    '#field_name' => $form['#field_name'],
    '#type_name' => $form['#type_name'],
    '#tree' => $form['#tree'],
  );
  $new_form['select_other_list'] = array(
    '#id' => 'edit-field-' . $field_name . '-select-other-list',
    '#name' => $form['#field_name'] . '[select_other_list]',
    '#parents' => array(
      'cck_select_other',
    ),
    '#type' => 'select',
    '#title' => t(''),
    '#description' => t('Select other to enter your own option.'),
    '#options' => $options,
    '#default_value' => $select_def,
    '#value' => $select_def,
    '#weight' => -10,
  );
  $new_form['select_other_text_input'] = array(
    '#id' => 'edit-field-' . $field_name . '-select-other-text-input',
    '#name' => $form['#field_name'] . '[select_other_text_input]',
    '#parents' => array(
      'cck_select_other',
    ),
    '#type' => 'textfield',
    '#title' => t('Specify other'),
    '#default_value' => $select_def == 'other' ? check_plain($def) : '',
    '#value' => $select_def == 'other' ? check_plain($def) : '',
  );
  return $new_form;
}

/**
 * Post-render callback to add javascript functionality
 * @param $form
 * @return $form
 */
function cck_select_other_post_render($content, $elements) {
  static $js;
  $field_name = substr($elements['#field_name'], 6);
  if (!$js) {
    drupal_add_js(array(
      'CCKSelectOther' => array(
        'field' => $field_name,
      ),
    ), 'setting');
    drupal_add_js(drupal_get_path('module', 'cck_select_other') . '/cck_select_other.js');
    $js = TRUE;
  }
  else {
    drupal_add_js(array(
      'CCKSelectOther' => array(
        'field' => $field_name,
      ),
    ), 'setting');
  }
  return $content;
}

/**
 * Implementation of hook_views_api().
 */
function cck_select_other_views_api() {
  return array(
    'api' => '2',
    'path' => drupal_get_path('module', 'cck_select_other') . '/views',
  );
}

Functions

Namesort descending Description
cck_select_other_elements Implementation of hook_elements
cck_select_other_options Helper function for finding the options list for this field.
cck_select_other_post_render Post-render callback to add javascript functionality
cck_select_other_pre_render Pre render callback for the form so we can recreate the fake form after it gets blown away by the CCK process callback.
cck_select_other_process Process an individual element.
cck_select_other_views_api Implementation of hook_views_api().
cck_select_other_widget Implementation of hook_widget().
cck_select_other_widget_info Implementation of hook_widget_info().
cck_select_other_widget_settings Implementation of hook_widget_settings