[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/modules/form_builder/options_element/ -> options_element.module (source)

   1  <?php
   2  // $Id: options_element.module,v 1.8 2009/01/13 03:39:56 quicksketch Exp $
   3  
   4  /**
   5   * @file
   6   * Defines an "options" form element type for entering select list options.
   7   */
   8  
   9  /**
  10   * Implementation of hook_elements().
  11   *
  12   * Defines the #type = 'options' form element type.
  13   *
  14   * The 'options' form element type is useful when collecting a series of
  15   * values in a list. The values within the list may optionally have unique
  16   * keys, such as that in a array structure. In addition, a default choice
  17   * (or several default choices) may be selected by the user.
  18   *
  19   * @code
  20   * $element['options'] = array(
  21   *   'type' => 'options',
  22   *   'limit' => 20,
  23   *   'optgroups' => FALSE,
  24   *   'multiple' => FALSE,
  25   *   'options' => array(
  26   *     'foo' => 'foo',
  27   *     'bar' => 'bar',
  28   *     'baz' => 'baz',
  29   *   ),
  30   *   'default_value' => 'foo'
  31   *   'key_type' => 'associative',
  32   * );
  33   * @endcode
  34   *
  35   * Properties for the 'options' element include:
  36   * - limit: The maximum number of options that can be added to a list. Defaults
  37   *   to 100.
  38   * - optgroups: If nesting of options is supported, up to one level. This is
  39   *   used when building a select HTML element that uses optgroups. Defaults to
  40   *   FALSE.
  41   * - multiple: Affects the number of default values that may be selected.
  42   * - default_value: The key(s) for the options that are currently selected. If
  43   *   #multiple is TRUE then, the default value is an array, otherwise it is a
  44   *   string.
  45   * - options: An array of options currently within the list.
  46   * - key_type: The method by which keys are determined for each value in the
  47   *   option list. Available options include:
  48   *   - numeric: Each value is automatically given a unique numeric ID. This can
  49   *     be useful when wanting duplicate values in a list and not have to bother
  50   *     the end-user for keys.
  51   *   - associative: Keys are automatically mapped from the user-entered values.
  52   *     This is equivalent to making key|value pairs, but both the key and value
  53   *     are the same. Each key must be unique.
  54   *   - custom: Keys are manually entered by the end user. A second set of
  55   *     textfields are presented to let the user provide keys as well as values.
  56   *   - none: No keys are specified at all. This effectively creates numeric keys
  57   *     but unlike numeric keys, the keys are renumbered if the options in the
  58   *     list are rearranged.
  59   * - key_type_toggle: If specified, a checkbox will be added that allows the
  60   *   user to toggle between the current "associative" key type and the "custom"
  61   *   key type, letting them customize the keys as desired. This option has no
  62   *   effect with "numeric" or "none" key types.
  63   *   @code
  64   *   $element['options'] = array(
  65   *     'type' => 'options',
  66   *     'key_type' => 'associative',
  67   *     'key_type_toggle' => t('Custom keys'),
  68   *   );
  69   *   @endcode
  70   */
  71  function options_element_elements() {
  72    $type = array();
  73  
  74    $type['options'] = array(
  75      '#input' => TRUE,
  76      '#process' => array('form_options_expand'),
  77      '#limit' => 100,
  78      '#optgroups' => TRUE,
  79      '#options' => array(),
  80      '#key_type' => 'associative',
  81    );
  82  
  83    return $type;
  84  }
  85  
  86  /**
  87   * Implementation of hook_theme().
  88   */
  89  function options_element_theme() {
  90    return array(
  91      'options' => array(
  92        'arguments' => array('element' => NULL),
  93      ),
  94    );
  95  }
  96  
  97  /**
  98   * Expand the "options" form element type.
  99   *
 100   * The "options" type is simply an enhanced textarea that makes it easier to
 101   * create key|value pairs and put items into optgroups.
 102   */
 103  function form_options_expand($element) {
 104    $element['#options'] = isset($element['#options']) ? $element['#options'] : array();
 105    $element['#multiple'] = isset($element['#multiple']) ? $element['#multiple'] : FALSE;
 106  
 107    $element['#tree'] = TRUE;
 108    $element['#theme'] = 'options';
 109  
 110    // Add the key type toggle checkbox.
 111    if (!isset($element['key_type']) && !empty($element['#key_type_toggle'])) {
 112      $element['key_type'] = array(
 113        '#title' => is_string($element['#key_type_toggle']) ? $element['#key_type_toggle'] : t('Customize keys'),
 114        '#type' => 'checkbox',
 115        '#return_value' => 'custom',
 116        '#default_value' => $element['#key_type'] == 'custom' ? 'custom' : '',
 117        '#attributes' => array('class' => 'key-type-toggle'),
 118        '#description' => t('Customizing the keys will allow you to save one value internally while showing a different option to the user. Specifying keys manually will let you change the values later without loosing data.'),
 119      );
 120    }
 121  
 122    // Add the multiple value toggle checkbox.
 123    if (!isset($element['multiple']) && !empty($element['#multiple_toggle'])) {
 124      $element['multiple'] = array(
 125        '#title' => is_string($element['#multiple_toggle']) ? $element['#multiple_toggle'] : t('Allow multiple values'),
 126        '#type' => 'checkbox',
 127        '#default_value' => !empty($element['#multiple']),
 128        '#attributes' => array('class' => 'multiple-toggle'),
 129        '#description' => t('Multiple values will let users select multiple items in this list.'),
 130      );
 131    }
 132  
 133    // Add the main textfield for adding options.
 134    if (!isset($element['options'])) {
 135      $element['options_field'] = array(
 136        '#type' => 'textarea',
 137        '#resizable' => TRUE,
 138        '#cols' => 60,
 139        '#rows' => 5,
 140        '#value' => isset($element['#options']) ? form_options_to_text($element['#options'], $element['#key_type']) : '',
 141        '#required' => isset($element['#required']) ? $element['#required'] : FALSE,
 142        '#description' => t('List options one option per line.'),
 143      );
 144  
 145      if ($element['#key_type'] == 'numeric' || $element['#key_type'] == 'custom') {
 146        $element['options_field']['#description'] .= ' ' . t('Key-value pairs may be specified by separating each option with pipes, such as <em>key|value</em>.');
 147      }
 148  
 149      if (!empty($element['#key_type_toggle'])) {
 150        $element['options_field']['#description'] .= ' ' . t('If the %toggle field is checked, key-value pairs may be specified by separating each option with pipes, such as <em>key|value</em>.', array('%toggle' => $element['key_type']['#title']));
 151      }
 152  
 153      if ($element['#key_type'] == 'numeric') {
 154        $element['options_field']['#description'] .= ' ' . t('This field requires all specified keys to be integers.');
 155      }
 156    }
 157  
 158    // Add the field for storing default values.
 159    if (!isset($element['default_value_field'])) {
 160      $element['default_value_field'] = array(
 161        '#title' => t('Default value'),
 162        '#type' => 'textfield',
 163        '#size' => 60,
 164        '#value' => isset($element['#default_value']) ? ($element['#multiple'] ? implode(', ', (array) $element['#default_value']) : $element['#default_value']) : '',
 165        '#description' => t('Specify the keys that should be selected by default.'),
 166      );
 167      if ($element['#multiple']) {
 168        $element['default_value_field']['#description'] .= ' ' . t('Multiple default values may be specified by separating keys with commas.');
 169      }
 170    }
 171  
 172    // Remove properties that will confuse the FAPI.
 173    unset($element['#options']);
 174    $element['#required'] = FALSE;
 175  
 176    return $element;
 177  }
 178  
 179  /**
 180   * Validate the "options" form element type.
 181   *
 182   * This function adjusts the value of the element from a text value to an array.
 183   */
 184  function form_type_options_value(&$element, $edit = FALSE) {
 185    if ($edit === FALSE) {
 186       return array(
 187         'options' => isset($element['#options']) ? $element['#options'] : array(),
 188         'default_value' => isset($element['#default_value']) ? $element['#default_value'] : '',
 189       );
 190    }
 191    else {
 192      // Change the key type if a new type is specified.
 193      if (!empty($element['#key_type_toggle'])) {
 194        $element['#key_type'] = empty($edit['key_type']) ? 'associative' : 'custom';
 195      }
 196  
 197      // Convert text to an array of options.
 198      $duplicates = array();
 199      $options = form_options_from_text($edit['options_field'], $element['#key_type'], empty($element['#optgroups']), $duplicates);
 200  
 201      // Check if a key is used multiple times.
 202      if (count($duplicates) == 1) {
 203        form_error($element, t('The key %key has been used multiple times. Each key must be unique to display properly.', array('%key' => array_pop($duplicates))));
 204      }
 205      elseif (!empty($duplicates)) {
 206        array_walk($duplicates, 'check_plain');
 207        $duplicate_list = theme('item_list', $duplicates);
 208        form_error($element, t('The following keys have been used multiple times. Each key must be unique to display properly.') . $duplicate_list);
 209      }
 210  
 211      // Check if no options are specified.
 212      if (empty($options) && $element['#required']) {
 213        form_error($element, t('At least one option must be specified.'));
 214      }
 215  
 216      // Check for numeric keys if needed.
 217      if ($element['#key_type'] == 'numeric') {
 218        foreach ($options as $key => $value) {
 219          if (!is_int($key)) {
 220            form_error($element, t('The keys for the %title field must be integers.', array('%title' => $element['#title'])));
 221            break;
 222          }
 223        }
 224      }
 225  
 226      // Check that the limit of options has not been exceeded.
 227      if (!empty($element['#limit'])) {
 228        $count = 0;
 229        foreach ($options as $value) {
 230          if (is_array($value)) {
 231            $count += count($value);
 232          }
 233          else {
 234            $count++;
 235          }
 236        }
 237        if ($count > $element['#limit']) {
 238          form_error($element, t('The %title field supports a maximum of @count options. Please reduce the number of options.', array('%title' => $element['#title'], '@count' => $element['#limit'])));
 239        }
 240      }
 241  
 242      // Convert default value.
 243      if ($element['#multiple']) {
 244        $default_value = explode(',', $edit['default_value_field']);
 245        foreach ($default_value as $key => &$value) {
 246          $value = trim($value);
 247          if ($value === '') {
 248            unset($default_value[$key]);
 249          }
 250        }
 251      }
 252      else {
 253        $default_value = $edit['default_value_field'];
 254      }
 255  
 256      return array(
 257        'options' => $options,
 258        'default_value' => $default_value,
 259      );
 260    }
 261  }
 262  
 263  function theme_options($element) {
 264    drupal_add_js('misc/tabledrag.js');
 265    drupal_add_js(drupal_get_path('module', 'options_element') .'/options_element.js');
 266    drupal_add_css(drupal_get_path('module', 'options_element') .'/options_element.css');
 267  
 268    $classes = array();
 269    if (isset($element['#attributes']['class'])) {
 270      $classes[] = $element['#attributes']['class'];
 271    }
 272  
 273    $classes[] = 'form-options';
 274    $classes[] = 'options-key-type-'. $element['#key_type'];
 275  
 276    if (isset($element['#optgroups']) && $element['#optgroups']) {
 277      $classes[] = 'options-optgroups';
 278    }
 279  
 280    if (isset($element['#multiple']) && $element['#multiple']) {
 281      $classes[] = 'options-multiple';
 282    }
 283  
 284    $options = '';
 285    $options .= drupal_render($element['options_field']);
 286    $options .= drupal_render($element['default_value_field']);
 287  
 288    $settings = '';
 289    if (isset($element['key_type'])) {
 290      $settings .= drupal_render($element['key_type']);
 291    }
 292    if (isset($element['multiple'])) {
 293      $settings .= drupal_render($element['multiple']);
 294    }
 295  
 296    $output = '';
 297    $output .= '<div class="' . implode(' ', $classes) .'">';
 298    $output .= theme('fieldset', array(
 299      '#title' => t('Options'),
 300      '#collapsible' => FALSE,
 301      '#children' => $options,
 302      '#attributes' => array('class' => 'options'),
 303    ));
 304  
 305    if (!empty($settings)) {
 306      $output .= theme('fieldset', array(
 307        '#title' => t('Option settings'),
 308        '#collapsible' => FALSE,
 309        '#children' => $settings,
 310        '#attributes' => array('class' => 'option-settings'),
 311      ));
 312    }
 313    $output .= '</div>';
 314  
 315    return $output;
 316  }
 317  
 318  /**
 319   * Create a textual representation of options from an array.
 320   *
 321   * @param $options
 322   *   An array of options used in a select list.
 323   * @param $key_type
 324   *   How key/value pairs should be interpreted. Available options:
 325   *   - numeric
 326   *   - associative
 327   *   - custom
 328   *   - none
 329   */
 330  function form_options_to_text($options, $key_type) {
 331    $output = '';
 332    $previous_key = false;
 333    $all_options = array();
 334  
 335    foreach ($options as $key => $value) {
 336      // Convert groups.
 337      if (is_array($value)) {
 338        $output .= '<' . $key . '>' . "\n";
 339        foreach ($value as $subkey => $subvalue) {
 340          $output .= (($key_type == 'numeric' || $key_type == 'custom') ? $subkey . '|' : '') . $subvalue . "\n";
 341        }
 342        $previous_key = $key;
 343      }
 344      // Typical key|value pairs.
 345      else {
 346        // Exit out of any groups.
 347        if (isset($options[$previous_key]) && is_array($options[$previous_key])) {
 348          $output .= "<>\n";
 349        }
 350        // Skip empty rows.
 351        if ($options[$key] !== '') {
 352          if ($key_type == 'numeric' || $key_type == 'custom') {
 353            $output .= $key . '|' . $value . "\n";
 354          }
 355          else {
 356            $output .= $value . "\n";
 357          }
 358        }
 359        $previous_key = $key;
 360      }
 361    }
 362  
 363    return $output;
 364  }
 365  
 366  
 367  /**
 368   * Submit function for option lists for radios, checkboxes, or select lists.
 369   *
 370   * If the Key of the option is within < >, treat as an optgroup
 371   * 
 372   * <Group 1>
 373   *   creates an optgroup with the label "Group 1"
 374   * 
 375   * <>
 376   *   Unsets the current group, allowing items to be inserted at the root element.  
 377   */
 378  function form_options_from_text($text, $key_type, $flat = FALSE, &$duplicates = array()) {
 379    $options = array();
 380    $rows = array_filter(explode("\n", trim($text)));
 381    $group = FALSE;
 382  
 383    foreach ($rows as $option) {
 384      $option = trim($option);
 385      $matches = array();
 386  
 387      // Check if this row is a group.
 388      if (!$flat && preg_match('/^\<([^>]*)\>$/', $option, $matches)) {
 389        if ($matches[1] === '') {
 390          $group = FALSE;
 391        }
 392        elseif (!$flat) {
 393          $group = $matches[1];
 394        }
 395      }
 396      // Check if this row is a key|value pair.
 397      elseif (($key_type == 'custom' || $key_type == 'numeric') && preg_match('/^([^|]+)\|(.*)$/', $option, $matches)) {
 398        $key = $matches[1];
 399        $value = $matches[2];
 400        if ($group !== FALSE) {
 401          isset($options[$group][$key]) ? $duplicates[$key] = $key : $options[$group][$key] = $value;
 402        }
 403        else {
 404          isset($options[$key]) ? $duplicates[$key] = $key : $options[$key] = $value;
 405        }
 406      }
 407      // Check if this row is a straight value.
 408      else {
 409        if ($group !== FALSE) {
 410          if ($key_type != 'none') {
 411            isset($options[$group][$option]) ? $duplicates[$option] = $option : $options[$group][$option] = $option;
 412          }
 413          else {
 414            $options[$group][] = $option;
 415          }
 416        }
 417        else {
 418          if ($key_type != 'none') {
 419            isset($options[$option]) ? $duplicates[$option] = $option : $options[$option] = $option;
 420          }
 421          else {
 422            $options[] = $option;
 423          }
 424        }
 425      }
 426    }
 427  
 428    return $options;
 429  }


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7