| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |