[ Index ] |
|
Code source de Drupal 5.3 |
1 <?php 2 // $Id: form.inc,v 1.174.2.11 2007/07/26 19:16:45 drumm Exp $ 3 4 /** 5 * @defgroup form Form generation 6 * @{ 7 * Functions to enable the processing and display of HTML forms. 8 * 9 * Drupal uses these functions to achieve consistency in its form processing and 10 * presentation, while simplifying code and reducing the amount of HTML that 11 * must be explicitly generated by modules. 12 * 13 * The drupal_get_form() function handles retrieving, processing, and 14 * displaying a rendered HTML form for modules automatically. For example: 15 * 16 * // Display the user registration form. 17 * $output = drupal_get_form('user_register'); 18 * 19 * Forms can also be built and submitted programmatically without any user input 20 * using the drupal_execute() function. 21 * 22 * 23 * For information on the format of the structured arrays used to define forms, 24 * and more detailed explanations of the Form API workflow, see the 25 * @link http://api.drupal.org/api/HEAD/file/developer/topics/forms_api_reference.html reference @endlink 26 * and the @link http://api.drupal.org/api/HEAD/file/developer/topics/forms_api.html quickstart guide. @endlink 27 */ 28 29 /** 30 * Retrieves a form from a builder function, passes it on for 31 * processing, and renders the form or redirects to its destination 32 * as appropriate. In multi-step form scenarios, it handles properly 33 * processing the values using the previous step's form definition, 34 * then rendering the requested step for display. 35 * 36 * @param $form_id 37 * The unique string identifying the desired form. If a function 38 * with that name exists, it is called to build the form array. 39 * Modules that need to generate the same form (or very similar forms) 40 * using different $form_ids can implement hook_forms(), which maps 41 * different $form_id values to the proper form building function. Examples 42 * may be found in node_forms(), search_forms(), and user_forms(). 43 * @param ... 44 * Any additional arguments needed by the form building function. 45 * @return 46 * The rendered form. 47 */ 48 function drupal_get_form($form_id) { 49 // In multi-step form scenarios, the incoming $_POST values are not 50 // necessarily intended for the current form. We need to build 51 // a copy of the previously built form for validation and processing, 52 // then go on to the one that was requested if everything works. 53 54 $form_build_id = md5(mt_rand()); 55 if (isset($_POST['form_build_id']) && isset($_SESSION['form'][$_POST['form_build_id']]['args']) && $_POST['form_id'] == $form_id) { 56 // There's a previously stored multi-step form. We should handle 57 // IT first. 58 $stored = TRUE; 59 $args = $_SESSION['form'][$_POST['form_build_id']]['args']; 60 $form = call_user_func_array('drupal_retrieve_form', $args); 61 $form['#build_id'] = $_POST['form_build_id']; 62 } 63 else { 64 // We're coming in fresh; build things as they would be. If the 65 // form's #multistep flag is set, store the build parameters so 66 // the same form can be reconstituted for validation. 67 $args = func_get_args(); 68 $form = call_user_func_array('drupal_retrieve_form', $args); 69 if (isset($form['#multistep']) && $form['#multistep']) { 70 // Clean up old multistep form session data. 71 _drupal_clean_form_sessions(); 72 $_SESSION['form'][$form_build_id] = array('timestamp' => time(), 'args' => $args); 73 $form['#build_id'] = $form_build_id; 74 } 75 $stored = FALSE; 76 } 77 78 // Process the form, submit it, and store any errors if necessary. 79 drupal_process_form($args[0], $form); 80 81 if ($stored && !form_get_errors()) { 82 // If it's a stored form and there were no errors, we processed the 83 // stored form successfully. Now we need to build the form that was 84 // actually requested. We always pass in the current $_POST values 85 // to the builder function, as values from one stage of a multistep 86 // form can determine how subsequent steps are displayed. 87 $args = func_get_args(); 88 $args[] = $_POST; 89 $form = call_user_func_array('drupal_retrieve_form', $args); 90 unset($_SESSION['form'][$_POST['form_build_id']]); 91 if (isset($form['#multistep']) && $form['#multistep']) { 92 $_SESSION['form'][$form_build_id] = array('timestamp' => time(), 'args' => $args); 93 $form['#build_id'] = $form_build_id; 94 } 95 drupal_prepare_form($args[0], $form); 96 } 97 98 return drupal_render_form($args[0], $form); 99 } 100 101 102 /** 103 * Remove form information that's at least a day old from the 104 * $_SESSION['form'] array. 105 */ 106 function _drupal_clean_form_sessions() { 107 if (isset($_SESSION['form'])) { 108 foreach ($_SESSION['form'] as $build_id => $data) { 109 if ($data['timestamp'] < (time() - 84600)) { 110 unset($_SESSION['form'][$build_id]); 111 } 112 } 113 } 114 } 115 116 117 /** 118 * Retrieves a form using a form_id, populates it with $form_values, 119 * processes it, and returns any validation errors encountered. This 120 * function is the programmatic counterpart to drupal_get_form(). 121 * 122 * @param $form_id 123 * The unique string identifying the desired form. If a function 124 * with that name exists, it is called to build the form array. 125 * Modules that need to generate the same form (or very similar forms) 126 * using different $form_ids can implement hook_forms(), which maps 127 * different $form_id values to the proper form building function. Examples 128 * may be found in node_forms(), search_forms(), and user_forms(). 129 * @param $form_values 130 * An array of values mirroring the values returned by a given form 131 * when it is submitted by a user. 132 * @param ... 133 * Any additional arguments needed by the form building function. 134 * @return 135 * Any form validation errors encountered. 136 * 137 * For example: 138 * 139 * // register a new user 140 * $values['name'] = 'robo-user'; 141 * $values['mail'] = 'robouser@example.com'; 142 * $values['pass'] = 'password'; 143 * drupal_execute('user_register', $values); 144 * 145 * // Create a new node 146 * $node = array('type' => 'story'); 147 * $values['title'] = 'My node'; 148 * $values['body'] = 'This is the body text!'; 149 * $values['name'] = 'robo-user'; 150 * drupal_execute('story_node_form', $values, $node); 151 */ 152 function drupal_execute($form_id, $form_values) { 153 $args = func_get_args(); 154 155 $form_id = array_shift($args); 156 $form_values = array_shift($args); 157 array_unshift($args, $form_id); 158 159 if (isset($form_values)) { 160 $form = call_user_func_array('drupal_retrieve_form', $args); 161 $form['#post'] = $form_values; 162 return drupal_process_form($form_id, $form); 163 } 164 } 165 166 /** 167 * Retrieves the structured array that defines a given form. 168 * 169 * @param $form_id 170 * The unique string identifying the desired form. If a function 171 * with that name exists, it is called to build the form array. 172 * Modules that need to generate the same form (or very similar forms) 173 * using different $form_ids can implement hook_forms(), which maps 174 * different $form_id values to the proper form building function. 175 * @param ... 176 * Any additional arguments needed by the form building function. 177 */ 178 function drupal_retrieve_form($form_id) { 179 static $forms; 180 181 // We save two copies of the incoming arguments: one for modules to use 182 // when mapping form ids to builder functions, and another to pass to 183 // the builder function itself. We shift out the first argument -- the 184 // $form_id itself -- from the list to pass into the builder function, 185 // since it's already known. 186 $args = func_get_args(); 187 $saved_args = $args; 188 array_shift($args); 189 190 // We first check to see if there's a function named after the $form_id. 191 // If there is, we simply pass the arguments on to it to get the form. 192 if (!function_exists($form_id)) { 193 // In cases where many form_ids need to share a central builder function, 194 // such as the node editing form, modules can implement hook_forms(). It 195 // maps one or more form_ids to the correct builder functions. 196 // 197 // We cache the results of that hook to save time, but that only works 198 // for modules that know all their form_ids in advance. (A module that 199 // adds a small 'rate this comment' form to each comment in a list 200 // would need a unique form_id for each one, for example.) 201 // 202 // So, we call the hook if $forms isn't yet populated, OR if it doesn't 203 // yet have an entry for the requested form_id. 204 if (!isset($forms) || !isset($forms[$form_id])) { 205 $forms = module_invoke_all('forms', $saved_args); 206 } 207 $form_definition = $forms[$form_id]; 208 if (isset($form_definition['callback arguments'])) { 209 $args = array_merge($form_definition['callback arguments'], $args); 210 } 211 if (isset($form_definition['callback'])) { 212 $callback = $form_definition['callback']; 213 } 214 } 215 // If $callback was returned by a hook_forms() implementation, call it. 216 // Otherwise, call the function named after the form id. 217 $form = call_user_func_array(isset($callback) ? $callback : $form_id, $args); 218 219 // We store the original function arguments, rather than the final $arg 220 // value, so that form_alter functions can see what was originally 221 // passed to drupal_retrieve_form(). This allows the contents of #parameters 222 // to be saved and passed in at a later date to recreate the form. 223 $form['#parameters'] = $saved_args; 224 return $form; 225 } 226 227 /** 228 * This function is the heart of form API. The form gets built, validated and in 229 * appropriate cases, submitted. 230 * 231 * @param $form_id 232 * The unique string identifying the current form. 233 * @param $form 234 * An associative array containing the structure of the form. 235 * @return 236 * The path to redirect the user to upon completion. 237 */ 238 function drupal_process_form($form_id, &$form) { 239 global $form_values, $form_submitted, $user, $form_button_counter; 240 static $saved_globals = array(); 241 // In some scenarios, this function can be called recursively. Pushing any pre-existing 242 // $form_values and form submission data lets us start fresh without clobbering work done 243 // in earlier recursive calls. 244 array_push($saved_globals, array($form_values, $form_submitted, $form_button_counter)); 245 246 $form_values = array(); 247 $form_submitted = FALSE; 248 $form_button_counter = array(0, 0); 249 250 drupal_prepare_form($form_id, $form); 251 if (($form['#programmed']) || (!empty($_POST) && (($_POST['form_id'] == $form_id)))) { 252 drupal_validate_form($form_id, $form); 253 // IE does not send a button value when there is only one submit button (and no non-submit buttons) 254 // and you submit by pressing enter. 255 // In that case we accept a submission without button values. 256 if ((($form['#programmed']) || $form_submitted || (!$form_button_counter[0] && $form_button_counter[1])) && !form_get_errors()) { 257 $redirect = drupal_submit_form($form_id, $form); 258 if (!$form['#programmed']) { 259 drupal_redirect_form($form, $redirect); 260 } 261 } 262 } 263 264 // We've finished calling functions that alter the global values, so we can 265 // restore the ones that were there before this function was called. 266 list($form_values, $form_submitted, $form_button_counter) = array_pop($saved_globals); 267 return $redirect; 268 } 269 270 /** 271 * Prepares a structured form array by adding required elements, 272 * executing any hook_form_alter functions, and optionally inserting 273 * a validation token to prevent tampering. 274 * 275 * @param $form_id 276 * A unique string identifying the form for validation, submission, 277 * theming, and hook_form_alter functions. 278 * @param $form 279 * An associative array containing the structure of the form. 280 */ 281 function drupal_prepare_form($form_id, &$form) { 282 global $user; 283 284 $form['#type'] = 'form'; 285 286 if (!isset($form['#post'])) { 287 $form['#post'] = $_POST; 288 $form['#programmed'] = FALSE; 289 } 290 else { 291 $form['#programmed'] = TRUE; 292 } 293 294 // In multi-step form scenarios, this id is used to identify 295 // a unique instance of a particular form for retrieval. 296 if (isset($form['#build_id'])) { 297 $form['form_build_id'] = array( 298 '#type' => 'hidden', 299 '#value' => $form['#build_id'], 300 '#id' => $form['#build_id'], 301 '#name' => 'form_build_id', 302 ); 303 } 304 305 // If $base is set, it is used in place of $form_id when constructing validation, 306 // submission, and theming functions. Useful for mapping many similar or duplicate 307 // forms with different $form_ids to the same processing functions. 308 if (isset($form['#base'])) { 309 $base = $form['#base']; 310 } 311 312 // Add a token, based on either #token or form_id, to any form displayed to 313 // authenticated users. This ensures that any submitted form was actually 314 // requested previously by the user and protects against cross site request 315 // forgeries. 316 if (isset($form['#token'])) { 317 if ($form['#token'] === FALSE || $user->uid == 0 || $form['#programmed']) { 318 unset($form['#token']); 319 } 320 else { 321 $form['form_token'] = array('#type' => 'token', '#default_value' => drupal_get_token($form['#token'])); 322 } 323 } 324 else if ($user->uid && !$form['#programmed']) { 325 $form['#token'] = $form_id; 326 $form['form_token'] = array( 327 '#id' => form_clean_id('edit-'. $form_id .'-form-token'), 328 '#type' => 'token', 329 '#default_value' => drupal_get_token($form['#token']), 330 ); 331 } 332 333 334 if (isset($form_id)) { 335 $form['form_id'] = array('#type' => 'hidden', '#value' => $form_id, '#id' => form_clean_id("edit-$form_id")); 336 } 337 if (!isset($form['#id'])) { 338 $form['#id'] = form_clean_id($form_id); 339 } 340 341 $form += _element_info('form'); 342 343 if (!isset($form['#validate'])) { 344 if (function_exists($form_id .'_validate')) { 345 $form['#validate'] = array($form_id .'_validate' => array()); 346 } 347 elseif (function_exists($base .'_validate')) { 348 $form['#validate'] = array($base .'_validate' => array()); 349 } 350 } 351 352 if (!isset($form['#submit'])) { 353 if (function_exists($form_id .'_submit')) { 354 // We set submit here so that it can be altered. 355 $form['#submit'] = array($form_id .'_submit' => array()); 356 } 357 elseif (function_exists($base .'_submit')) { 358 $form['#submit'] = array($base .'_submit' => array()); 359 } 360 } 361 362 foreach (module_implements('form_alter') as $module) { 363 $function = $module .'_form_alter'; 364 $function($form_id, $form); 365 } 366 367 $form = form_builder($form_id, $form); 368 } 369 370 371 /** 372 * Validates user-submitted form data from a global variable using 373 * the validate functions defined in a structured form array. 374 * 375 * @param $form_id 376 * A unique string identifying the form for validation, submission, 377 * theming, and hook_form_alter functions. 378 * @param $form 379 * An associative array containing the structure of the form. 380 * 381 */ 382 function drupal_validate_form($form_id, $form) { 383 global $form_values; 384 static $validated_forms = array(); 385 386 if (isset($validated_forms[$form_id])) { 387 return; 388 } 389 390 // If the session token was set by drupal_prepare_form(), ensure that it 391 // matches the current user's session. 392 if (isset($form['#token'])) { 393 if (!drupal_valid_token($form_values['form_token'], $form['#token'])) { 394 // Setting this error will cause the form to fail validation. 395 form_set_error('form_token', t('Validation error, please try again. If this error persists, please contact the site administrator.')); 396 } 397 } 398 399 _form_validate($form, $form_id); 400 $validated_forms[$form_id] = TRUE; 401 } 402 403 /** 404 * Processes user-submitted form data from a global variable using 405 * the submit functions defined in a structured form array. 406 * 407 * @param $form_id 408 * A unique string identifying the form for validation, submission, 409 * theming, and hook_form_alter functions. 410 * @param $form 411 * An associative array containing the structure of the form. 412 * @return 413 * A string containing the path of the page to display when processing 414 * is complete. 415 * 416 */ 417 function drupal_submit_form($form_id, $form) { 418 global $form_values; 419 $default_args = array($form_id, &$form_values); 420 $submitted = FALSE; 421 $goto = NULL; 422 423 if (isset($form['#submit'])) { 424 foreach ($form['#submit'] as $function => $args) { 425 if (function_exists($function)) { 426 $args = array_merge($default_args, (array) $args); 427 // Since we can only redirect to one page, only the last redirect 428 // will work. 429 $redirect = call_user_func_array($function, $args); 430 $submitted = TRUE; 431 if (isset($redirect)) { 432 $goto = $redirect; 433 } 434 } 435 } 436 } 437 438 return $goto; 439 } 440 441 /** 442 * Renders a structured form array into themed HTML. 443 * 444 * @param $form_id 445 * A unique string identifying the form for validation, submission, 446 * theming, and hook_form_alter functions. 447 * @param $form 448 * An associative array containing the structure of the form. 449 * @return 450 * A string containing the path of the page to display when processing 451 * is complete. 452 * 453 */ 454 function drupal_render_form($form_id, &$form) { 455 // Don't override #theme if someone already set it. 456 if (isset($form['#base'])) { 457 $base = $form['#base']; 458 } 459 460 if (!isset($form['#theme'])) { 461 if (theme_get_function($form_id)) { 462 $form['#theme'] = $form_id; 463 } 464 elseif (theme_get_function($base)) { 465 $form['#theme'] = $base; 466 } 467 } 468 469 if (isset($form['#pre_render'])) { 470 foreach ($form['#pre_render'] as $function) { 471 if (function_exists($function)) { 472 $function($form_id, $form); 473 } 474 } 475 } 476 477 $output = drupal_render($form); 478 return $output; 479 } 480 481 /** 482 * Redirect the user to a URL after a form has been processed. 483 * 484 * @param $form 485 * An associative array containing the structure of the form. 486 * @param $redirect 487 * An optional string containing the destination path to redirect 488 * to if none is specified by the form. 489 * 490 */ 491 function drupal_redirect_form($form, $redirect = NULL) { 492 if (isset($redirect)) { 493 $goto = $redirect; 494 } 495 if (isset($form['#redirect'])) { 496 $goto = $form['#redirect']; 497 } 498 if ($goto !== FALSE) { 499 if (is_array($goto)) { 500 call_user_func_array('drupal_goto', $goto); 501 } 502 elseif (!isset($goto)) { 503 drupal_goto($_GET['q']); 504 } 505 else { 506 drupal_goto($goto); 507 } 508 } 509 } 510 511 /** 512 * Performs validation on form elements. First ensures required fields are 513 * completed, #maxlength is not exceeded, and selected options were in the 514 * list of options given to the user. Then calls user-defined validators. 515 * 516 * @param $elements 517 * An associative array containing the structure of the form. 518 * @param $form_id 519 * A unique string identifying the form for validation, submission, 520 * theming, and hook_form_alter functions. 521 */ 522 function _form_validate($elements, $form_id = NULL) { 523 // Recurse through all children. 524 foreach (element_children($elements) as $key) { 525 if (isset($elements[$key]) && $elements[$key]) { 526 _form_validate($elements[$key]); 527 } 528 } 529 /* Validate the current input */ 530 if (!isset($elements['#validated']) || !$elements['#validated']) { 531 if (isset($elements['#needs_validation'])) { 532 // An empty textfield returns '' so we use empty(). An empty checkbox 533 // and a textfield could return '0' and empty('0') returns TRUE so we 534 // need a special check for the '0' string. 535 if ($elements['#required'] && empty($elements['#value']) && $elements['#value'] !== '0') { 536 form_error($elements, t('!name field is required.', array('!name' => $elements['#title']))); 537 } 538 539 // Verify that the value is not longer than #maxlength. 540 if (isset($elements['#maxlength']) && drupal_strlen($elements['#value']) > $elements['#maxlength']) { 541 form_error($elements, t('!name cannot be longer than %max characters but is currently %length characters long.', array('!name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'], '%max' => $elements['#maxlength'], '%length' => drupal_strlen($elements['#value'])))); 542 } 543 544 // Add legal choice check if element has #options. Can be skipped, but 545 // then you must validate your own element. 546 if (isset($elements['#options']) && isset($elements['#value']) && !isset($elements['#DANGEROUS_SKIP_CHECK'])) { 547 if ($elements['#type'] == 'select') { 548 $options = form_options_flatten($elements['#options']); 549 } 550 else { 551 $options = $elements['#options']; 552 } 553 if (is_array($elements['#value'])) { 554 $value = $elements['#type'] == 'checkboxes' ? array_keys(array_filter($elements['#value'])) : $elements['#value']; 555 foreach ($value as $v) { 556 if (!isset($options[$v])) { 557 form_error($elements, t('An illegal choice has been detected. Please contact the site administrator.')); 558 watchdog('form', t('Illegal choice %choice in !name element.', array('%choice' => $v, '!name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'])), WATCHDOG_ERROR); 559 } 560 } 561 } 562 elseif (!isset($options[$elements['#value']])) { 563 form_error($elements, t('An illegal choice has been detected. Please contact the site administrator.')); 564 watchdog('form', t('Illegal choice %choice in %name element.', array('%choice' => $elements['#value'], '%name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'])), WATCHDOG_ERROR); 565 } 566 } 567 } 568 569 // Call user-defined validators. 570 if (isset($elements['#validate'])) { 571 foreach ($elements['#validate'] as $function => $args) { 572 $args = array_merge(array($elements), $args); 573 // For the full form we hand over a copy of $form_values. 574 if (isset($form_id)) { 575 $args = array_merge(array($form_id, $GLOBALS['form_values']), $args); 576 } 577 if (function_exists($function)) { 578 call_user_func_array($function, $args); 579 } 580 } 581 } 582 $elements['#validated'] = TRUE; 583 } 584 } 585 586 /** 587 * File an error against a form element. If the name of the element is 588 * edit[foo][bar] then you may pass either foo or foo][bar as $name 589 * foo will set an error for all its children. 590 */ 591 function form_set_error($name = NULL, $message = '') { 592 static $form = array(); 593 if (isset($name) && !isset($form[$name])) { 594 $form[$name] = $message; 595 if ($message) { 596 drupal_set_message($message, 'error'); 597 } 598 } 599 return $form; 600 } 601 602 /** 603 * Return an associative array of all errors. 604 */ 605 function form_get_errors() { 606 $form = form_set_error(); 607 if (!empty($form)) { 608 return $form; 609 } 610 } 611 612 /** 613 * Return the error message filed against the form with the specified name. 614 */ 615 function form_get_error($element) { 616 $form = form_set_error(); 617 $key = $element['#parents'][0]; 618 if (isset($form[$key])) { 619 return $form[$key]; 620 } 621 $key = implode('][', $element['#parents']); 622 if (isset($form[$key])) { 623 return $form[$key]; 624 } 625 } 626 627 /** 628 * Flag an element as having an error. 629 */ 630 function form_error(&$element, $message = '') { 631 $element['#error'] = TRUE; 632 form_set_error(implode('][', $element['#parents']), $message); 633 } 634 635 /** 636 * Adds some required properties to each form element, which are used 637 * internally in the form API. This function also automatically assigns 638 * the value property from the $edit array, provided the element doesn't 639 * already have an assigned value. 640 * 641 * @param $form_id 642 * A unique string identifying the form for validation, submission, 643 * theming, and hook_form_alter functions. 644 * @param $form 645 * An associative array containing the structure of the form. 646 */ 647 function form_builder($form_id, $form) { 648 global $form_values, $form_submitted, $form_button_counter; 649 650 // Initialize as unprocessed. 651 $form['#processed'] = FALSE; 652 653 /* Use element defaults */ 654 if ((!empty($form['#type'])) && ($info = _element_info($form['#type']))) { 655 // Overlay $info onto $form, retaining preexisting keys in $form. 656 $form += $info; 657 } 658 659 if (isset($form['#input']) && $form['#input']) { 660 if (!isset($form['#name'])) { 661 $name = array_shift($form['#parents']); 662 $form['#name'] = $name; 663 if ($form['#type'] == 'file') { 664 // To make it easier to handle $_FILES in file.inc, we place all 665 // file fields in the 'files' array. Also, we do not support 666 // nested file names. 667 $form['#name'] = 'files['. $form['#name'] .']'; 668 } 669 elseif (count($form['#parents'])) { 670 $form['#name'] .= '['. implode('][', $form['#parents']) .']'; 671 } 672 array_unshift($form['#parents'], $name); 673 } 674 if (!isset($form['#id'])) { 675 $form['#id'] = form_clean_id('edit-'. implode('-', $form['#parents'])); 676 } 677 678 if (isset($form['#disabled']) && $form['#disabled']) { 679 $form['#attributes']['disabled'] = 'disabled'; 680 } 681 682 if (!isset($form['#value']) && !array_key_exists('#value', $form)) { 683 if (($form['#programmed']) || ((!isset($form['#access']) || $form['#access']) && isset($form['#post']) && (isset($form['#post']['form_id']) && $form['#post']['form_id'] == $form_id))) { 684 $edit = $form['#post']; 685 foreach ($form['#parents'] as $parent) { 686 $edit = isset($edit[$parent]) ? $edit[$parent] : NULL; 687 } 688 if (!$form['#programmed'] || isset($edit)) { 689 switch ($form['#type']) { 690 case 'checkbox': 691 $form['#value'] = !empty($edit) ? $form['#return_value'] : 0; 692 break; 693 694 case 'select': 695 if (isset($form['#multiple']) && $form['#multiple']) { 696 if (isset($edit) && is_array($edit)) { 697 $form['#value'] = drupal_map_assoc($edit); 698 } 699 else { 700 $form['#value'] = array(); 701 } 702 } 703 elseif (isset($edit)) { 704 $form['#value'] = $edit; 705 } 706 break; 707 708 case 'textfield': 709 if (isset($edit)) { 710 // Equate $edit to the form value to ensure it's marked for 711 // validation. 712 $edit = str_replace(array("\r", "\n"), '', $edit); 713 $form['#value'] = $edit; 714 } 715 break; 716 717 case 'token': 718 $form['#value'] = (string)$edit; 719 break; 720 721 default: 722 if (isset($edit)) { 723 $form['#value'] = $edit; 724 } 725 } 726 // Mark all posted values for validation. 727 if ((isset($form['#value']) && $form['#value'] === $edit) || (isset($form['#required']) && $form['#required'])) { 728 $form['#needs_validation'] = TRUE; 729 } 730 } 731 } 732 if (!isset($form['#value'])) { 733 $function = $form['#type'] . '_value'; 734 if (function_exists($function)) { 735 $function($form); 736 } 737 else { 738 $form['#value'] = isset($form['#default_value']) ? $form['#default_value'] : ''; 739 } 740 } 741 } 742 if (isset($form['#executes_submit_callback'])) { 743 // Count submit and non-submit buttons. 744 $form_button_counter[$form['#executes_submit_callback']]++; 745 // See if a submit button was pressed. 746 if (isset($form['#post'][$form['#name']]) && $form['#post'][$form['#name']] == $form['#value']) { 747 $form_submitted = $form_submitted || $form['#executes_submit_callback']; 748 749 // In most cases, we want to use form_set_value() to manipulate the 750 // global variables. In this special case, we want to make sure that 751 // the value of this element is listed in $form_variables under 'op'. 752 $form_values[$form['#name']] = $form['#value']; 753 } 754 } 755 } 756 757 // Allow for elements to expand to multiple elements, e.g., radios, 758 // checkboxes and files. 759 if (isset($form['#process']) && !$form['#processed']) { 760 foreach ($form['#process'] as $process => $args) { 761 if (function_exists($process)) { 762 $args = array_merge(array($form), array($edit), $args); 763 $form = call_user_func_array($process, $args); 764 } 765 } 766 $form['#processed'] = TRUE; 767 } 768 769 // Set the $form_values key that gets passed to validate and submit. 770 // We call this after #process gets called so that #process has a 771 // chance to update #value if desired. 772 if (isset($form['#input']) && $form['#input']) { 773 form_set_value($form, $form['#value']); 774 } 775 776 // We start off assuming all form elements are in the correct order. 777 $form['#sorted'] = TRUE; 778 779 // Recurse through all child elements. 780 $count = 0; 781 foreach (element_children($form) as $key) { 782 $form[$key]['#post'] = $form['#post']; 783 $form[$key]['#programmed'] = $form['#programmed']; 784 // Don't squash an existing tree value. 785 if (!isset($form[$key]['#tree'])) { 786 $form[$key]['#tree'] = $form['#tree']; 787 } 788 789 // Deny access to child elements if parent is denied. 790 if (isset($form['#access']) && !$form['#access']) { 791 $form[$key]['#access'] = FALSE; 792 } 793 794 // Don't squash existing parents value. 795 if (!isset($form[$key]['#parents'])) { 796 // Check to see if a tree of child elements is present. If so, 797 // continue down the tree if required. 798 $form[$key]['#parents'] = $form[$key]['#tree'] && $form['#tree'] ? array_merge($form['#parents'], array($key)) : array($key); 799 } 800 801 // Assign a decimal placeholder weight to preserve original array order. 802 if (!isset($form[$key]['#weight'])) { 803 $form[$key]['#weight'] = $count/1000; 804 } 805 else { 806 // If one of the child elements has a weight then we will need to sort 807 // later. 808 unset($form['#sorted']); 809 } 810 $form[$key] = form_builder($form_id, $form[$key]); 811 $count++; 812 } 813 814 if (isset($form['#after_build']) && !isset($form['#after_build_done'])) { 815 foreach ($form['#after_build'] as $function) { 816 if (function_exists($function)) { 817 $form = $function($form, $form_values); 818 } 819 } 820 $form['#after_build_done'] = TRUE; 821 } 822 823 return $form; 824 } 825 826 /** 827 * Use this function to make changes to form values in the form validate 828 * phase, so they will be available in the submit phase in $form_values. 829 * 830 * Specifically, if $form['#parents'] is array('foo', 'bar') 831 * and $value is 'baz' then this function will make 832 * $form_values['foo']['bar'] to be 'baz'. 833 * 834 * @param $form 835 * The form item. Keys used: #parents, #value 836 * @param $value 837 * The value for the form item. 838 */ 839 function form_set_value($form, $value) { 840 global $form_values; 841 _form_set_value($form_values, $form, $form['#parents'], $value); 842 } 843 844 /** 845 * Helper function for form_set_value(). 846 * 847 * We iterate over $parents and create nested arrays for them 848 * in $form_values if needed. Then we insert the value into 849 * the right array. 850 */ 851 function _form_set_value(&$form_values, $form, $parents, $value) { 852 $parent = array_shift($parents); 853 if (empty($parents)) { 854 $form_values[$parent] = $value; 855 } 856 else { 857 if (!isset($form_values[$parent])) { 858 $form_values[$parent] = array(); 859 } 860 _form_set_value($form_values[$parent], $form, $parents, $value); 861 } 862 return $form; 863 } 864 865 /** 866 * Retrieve the default properties for the defined element type. 867 */ 868 function _element_info($type, $refresh = NULL) { 869 static $cache; 870 871 $basic_defaults = array( 872 '#description' => NULL, 873 '#attributes' => array(), 874 '#required' => FALSE, 875 '#tree' => FALSE, 876 '#parents' => array() 877 ); 878 if (!isset($cache) || $refresh) { 879 $cache = array(); 880 foreach (module_implements('elements') as $module) { 881 $elements = module_invoke($module, 'elements'); 882 if (isset($elements) && is_array($elements)) { 883 $cache = array_merge_recursive($cache, $elements); 884 } 885 } 886 if (sizeof($cache)) { 887 foreach ($cache as $element_type => $info) { 888 $cache[$element_type] = array_merge_recursive($basic_defaults, $info); 889 } 890 } 891 } 892 893 return $cache[$type]; 894 } 895 896 function form_options_flatten($array, $reset = TRUE) { 897 static $return; 898 899 if ($reset) { 900 $return = array(); 901 } 902 903 foreach ($array as $key => $value) { 904 if (is_object($value)) { 905 form_options_flatten($value->option, FALSE); 906 } 907 else if (is_array($value)) { 908 form_options_flatten($value, FALSE); 909 } 910 else { 911 $return[$key] = 1; 912 } 913 } 914 915 return $return; 916 } 917 918 /** 919 * Format a dropdown menu or scrolling selection box. 920 * 921 * @param $element 922 * An associative array containing the properties of the element. 923 * Properties used: title, value, options, description, extra, multiple, required 924 * @return 925 * A themed HTML string representing the form element. 926 * 927 * It is possible to group options together; to do this, change the format of 928 * $options to an associative array in which the keys are group labels, and the 929 * values are associative arrays in the normal $options format. 930 */ 931 function theme_select($element) { 932 $select = ''; 933 $size = $element['#size'] ? ' size="' . $element['#size'] . '"' : ''; 934 _form_set_class($element, array('form-select')); 935 $multiple = isset($element['#multiple']) && $element['#multiple']; 936 return theme('form_element', $element, '<select name="'. $element['#name'] .''. ($multiple ? '[]' : '') .'"'. ($multiple ? ' multiple="multiple" ' : '') . drupal_attributes($element['#attributes']) .' id="'. $element['#id'] .'" '. $size .'>'. form_select_options($element) .'</select>'); 937 } 938 939 function form_select_options($element, $choices = NULL) { 940 if (!isset($choices)) { 941 $choices = $element['#options']; 942 } 943 // array_key_exists() accommodates the rare event where $element['#value'] is NULL. 944 // isset() fails in this situation. 945 $value_valid = isset($element['#value']) || array_key_exists('#value', $element); 946 $value_is_array = is_array($element['#value']); 947 $options = ''; 948 foreach ($choices as $key => $choice) { 949 if (is_array($choice)) { 950 $options .= '<optgroup label="'. $key .'">'; 951 $options .= form_select_options($element, $choice); 952 $options .= '</optgroup>'; 953 } 954 elseif (is_object($choice)) { 955 $options .= form_select_options($element, $choice->option); 956 } 957 else { 958 $key = (string)$key; 959 if ($value_valid && (!$value_is_array && (string)$element['#value'] === $key || ($value_is_array && in_array($key, $element['#value'])))) { 960 $selected = ' selected="selected"'; 961 } 962 else { 963 $selected = ''; 964 } 965 $options .= '<option value="'. check_plain($key) .'"'. $selected .'>'. check_plain($choice) .'</option>'; 966 } 967 } 968 return $options; 969 } 970 971 /** 972 * Traverses a select element's #option array looking for any values 973 * that hold the given key. Returns an array of indexes that match. 974 * 975 * This function is useful if you need to modify the options that are 976 * already in a form element; for example, to remove choices which are 977 * not valid because of additional filters imposed by another module. 978 * One example might be altering the choices in a taxonomy selector. 979 * To correctly handle the case of a multiple hierarchy taxonomy, 980 * #options arrays can now hold an array of objects, instead of a 981 * direct mapping of keys to labels, so that multiple choices in the 982 * selector can have the same key (and label). This makes it difficult 983 * to manipulate directly, which is why this helper function exists. 984 * 985 * This function does not support optgroups (when the elements of the 986 * #options array are themselves arrays), and will return FALSE if 987 * arrays are found. The caller must either flatten/restore or 988 * manually do their manipulations in this case, since returning the 989 * index is not sufficient, and supporting this would make the 990 * "helper" too complicated and cumbersome to be of any help. 991 * 992 * As usual with functions that can return array() or FALSE, do not 993 * forget to use === and !== if needed. 994 * 995 * @param $element 996 * The select element to search. 997 * @param $key 998 * The key to look for. 999 * @return 1000 * An array of indexes that match the given $key. Array will be 1001 * empty if no elements were found. FALSE if optgroups were found. 1002 */ 1003 function form_get_options($element, $key) { 1004 $keys = array(); 1005 foreach ($element['#options'] as $index => $choice) { 1006 if (is_array($choice)) { 1007 return FALSE; 1008 } 1009 else if (is_object($choice)) { 1010 if (isset($choice->option[$key])) { 1011 $keys[] = $index; 1012 } 1013 } 1014 else if ($index == $key) { 1015 $keys[] = $index; 1016 } 1017 } 1018 return $keys; 1019 } 1020 1021 /** 1022 * Format a group of form items. 1023 * 1024 * @param $element 1025 * An associative array containing the properties of the element. 1026 * Properties used: attributes, title, value, description, children, collapsible, collapsed 1027 * @return 1028 * A themed HTML string representing the form item group. 1029 */ 1030 function theme_fieldset($element) { 1031 if ($element['#collapsible']) { 1032 drupal_add_js('misc/collapse.js'); 1033 1034 if (!isset($element['#attributes']['class'])) { 1035 $element['#attributes']['class'] = ''; 1036 } 1037 1038 $element['#attributes']['class'] .= ' collapsible'; 1039 if ($element['#collapsed']) { 1040 $element['#attributes']['class'] .= ' collapsed'; 1041 } 1042 } 1043 1044 return '<fieldset' . drupal_attributes($element['#attributes']) .'>' . ($element['#title'] ? '<legend>'. $element['#title'] .'</legend>' : '') . ($element['#description'] ? '<div class="description">'. $element['#description'] .'</div>' : '') . $element['#children'] . $element['#value'] . "</fieldset>\n"; 1045 } 1046 1047 /** 1048 * Format a radio button. 1049 * 1050 * @param $element 1051 * An associative array containing the properties of the element. 1052 * Properties used: required, return_value, value, attributes, title, description 1053 * @return 1054 * A themed HTML string representing the form item group. 1055 */ 1056 function theme_radio($element) { 1057 _form_set_class($element, array('form-radio')); 1058 $output = '<input type="radio" '; 1059 $output .= 'name="' . $element['#name'] .'" '; 1060 $output .= 'value="'. $element['#return_value'] .'" '; 1061 $output .= (check_plain($element['#value']) == $element['#return_value']) ? ' checked="checked" ' : ' '; 1062 $output .= drupal_attributes($element['#attributes']) .' />'; 1063 if (!is_null($element['#title'])) { 1064 $output = '<label class="option">'. $output .' '. $element['#title'] .'</label>'; 1065 } 1066 1067 unset($element['#title']); 1068 return theme('form_element', $element, $output); 1069 } 1070 1071 /** 1072 * Format a set of radio buttons. 1073 * 1074 * @param $element 1075 * An associative array containing the properties of the element. 1076 * Properties used: title, value, options, description, required and attributes. 1077 * @return 1078 * A themed HTML string representing the radio button set. 1079 */ 1080 function theme_radios($element) { 1081 $class = 'form-radios'; 1082 if (isset($element['#attributes']['class'])) { 1083 $class .= ' '. $element['#attributes']['class']; 1084 } 1085 $element['#children'] = '<div class="'. $class .'">'. $element['#children'] .'</div>'; 1086 if ($element['#title'] || $element['#description']) { 1087 unset($element['#id']); 1088 return theme('form_element', $element, $element['#children']); 1089 } 1090 else { 1091 return $element['#children']; 1092 } 1093 } 1094 1095 /** 1096 * Format a password_confirm item. 1097 * 1098 * @param $element 1099 * An associative array containing the properties of the element. 1100 * Properties used: title, value, id, required, error. 1101 * @return 1102 * A themed HTML string representing the form item. 1103 */ 1104 function theme_password_confirm($element) { 1105 return theme('form_element', $element, $element['#children']); 1106 } 1107 1108 /* 1109 * Expand a password_confirm field into two text boxes. 1110 */ 1111 function expand_password_confirm($element) { 1112 $element['pass1'] = array( 1113 '#type' => 'password', 1114 '#title' => t('Password'), 1115 '#value' => $element['#value']['pass1'], 1116 '#required' => $element['#required'], 1117 ); 1118 $element['pass2'] = array( 1119 '#type' => 'password', 1120 '#title' => t('Confirm password'), 1121 '#value' => $element['#value']['pass2'], 1122 '#required' => $element['#required'], 1123 ); 1124 $element['#validate'] = array('password_confirm_validate' => array()); 1125 $element['#tree'] = TRUE; 1126 1127 if (isset($element['#size'])) { 1128 $element['pass1']['#size'] = $element['pass2']['#size'] = $element['#size']; 1129 } 1130 1131 return $element; 1132 } 1133 1134 /** 1135 * Validate password_confirm element. 1136 */ 1137 function password_confirm_validate($form) { 1138 $pass1 = trim($form['pass1']['#value']); 1139 if (!empty($pass1)) { 1140 $pass2 = trim($form['pass2']['#value']); 1141 if ($pass1 != $pass2) { 1142 form_error($form, t('The specified passwords do not match.')); 1143 } 1144 } 1145 elseif ($form['#required'] && !empty($form['#post'])) { 1146 form_error($form, t('Password field is required.')); 1147 } 1148 1149 // Password field must be converted from a two-element array into a single 1150 // string regardless of validation results. 1151 form_set_value($form['pass1'], NULL); 1152 form_set_value($form['pass2'], NULL); 1153 form_set_value($form, $pass1); 1154 1155 return $form; 1156 } 1157 1158 /** 1159 * Format a date selection element. 1160 * 1161 * @param $element 1162 * An associative array containing the properties of the element. 1163 * Properties used: title, value, options, description, required and attributes. 1164 * @return 1165 * A themed HTML string representing the date selection boxes. 1166 */ 1167 function theme_date($element) { 1168 return theme('form_element', $element, '<div class="container-inline">'. $element['#children'] .'</div>'); 1169 } 1170 1171 /** 1172 * Roll out a single date element. 1173 */ 1174 function expand_date($element) { 1175 // Default to current date 1176 if (empty($element['#value'])) { 1177 $element['#value'] = array('day' => format_date(time(), 'custom', 'j'), 1178 'month' => format_date(time(), 'custom', 'n'), 1179 'year' => format_date(time(), 'custom', 'Y')); 1180 } 1181 1182 $element['#tree'] = TRUE; 1183 1184 // Determine the order of day, month, year in the site's chosen date format. 1185 $format = variable_get('date_format_short', 'm/d/Y - H:i'); 1186 $sort = array(); 1187 $sort['day'] = max(strpos($format, 'd'), strpos($format, 'j')); 1188 $sort['month'] = max(strpos($format, 'm'), strpos($format, 'M')); 1189 $sort['year'] = strpos($format, 'Y'); 1190 asort($sort); 1191 $order = array_keys($sort); 1192 1193 // Output multi-selector for date. 1194 foreach ($order as $type) { 1195 switch ($type) { 1196 case 'day': 1197 $options = drupal_map_assoc(range(1, 31)); 1198 break; 1199 case 'month': 1200 $options = drupal_map_assoc(range(1, 12), 'map_month'); 1201 break; 1202 case 'year': 1203 $options = drupal_map_assoc(range(1900, 2050)); 1204 break; 1205 } 1206 $parents = $element['#parents']; 1207 $parents[] = $type; 1208 $element[$type] = array( 1209 '#type' => 'select', 1210 '#value' => $element['#value'][$type], 1211 '#attributes' => $element['#attributes'], 1212 '#options' => $options, 1213 ); 1214 } 1215 1216 return $element; 1217 } 1218 1219 /** 1220 * Validates the date type to stop dates like February 30, 2006. 1221 */ 1222 function date_validate($form) { 1223 if (!checkdate($form['#value']['month'], $form['#value']['day'], $form['#value']['year'])) { 1224 form_error($form, t('The specified date is invalid.')); 1225 } 1226 } 1227 1228 /** 1229 * Helper function for usage with drupal_map_assoc to display month names. 1230 */ 1231 function map_month($month) { 1232 return format_date(gmmktime(0, 0, 0, $month, 2, 1970), 'custom', 'M', 0); 1233 } 1234 1235 /** 1236 * Helper function to load value from default value for checkboxes. 1237 */ 1238 function checkboxes_value(&$form) { 1239 $value = array(); 1240 foreach ((array)$form['#default_value'] as $key) { 1241 $value[$key] = 1; 1242 } 1243 $form['#value'] = $value; 1244 } 1245 1246 /** 1247 * If no default value is set for weight select boxes, use 0. 1248 */ 1249 function weight_value(&$form) { 1250 if (isset($form['#default_value'])) { 1251 $form['#value'] = $form['#default_value']; 1252 } 1253 else { 1254 $form['#value'] = 0; 1255 } 1256 } 1257 1258 /** 1259 * Roll out a single radios element to a list of radios, 1260 * using the options array as index. 1261 */ 1262 function expand_radios($element) { 1263 if (count($element['#options']) > 0) { 1264 foreach ($element['#options'] as $key => $choice) { 1265 if (!isset($element[$key])) { 1266 $element[$key] = array('#type' => 'radio', '#title' => $choice, '#return_value' => check_plain($key), '#default_value' => $element['#default_value'], '#attributes' => $element['#attributes'], '#parents' => $element['#parents'], '#spawned' => TRUE); 1267 } 1268 } 1269 } 1270 return $element; 1271 } 1272 1273 /** 1274 * Format a form item. 1275 * 1276 * @param $element 1277 * An associative array containing the properties of the element. 1278 * Properties used: title, value, description, required, error 1279 * @return 1280 * A themed HTML string representing the form item. 1281 */ 1282 function theme_item($element) { 1283 return theme('form_element', $element, $element['#value'] . $element['#children']); 1284 } 1285 1286 /** 1287 * Format a checkbox. 1288 * 1289 * @param $element 1290 * An associative array containing the properties of the element. 1291 * Properties used: title, value, return_value, description, required 1292 * @return 1293 * A themed HTML string representing the checkbox. 1294 */ 1295 function theme_checkbox($element) { 1296 _form_set_class($element, array('form-checkbox')); 1297 $checkbox = '<input '; 1298 $checkbox .= 'type="checkbox" '; 1299 $checkbox .= 'name="'. $element['#name'] .'" '; 1300 $checkbox .= 'id="'. $element['#id'].'" ' ; 1301 $checkbox .= 'value="'. $element['#return_value'] .'" '; 1302 $checkbox .= $element['#value'] ? ' checked="checked" ' : ' '; 1303 $checkbox .= drupal_attributes($element['#attributes']) . ' />'; 1304 1305 if (!is_null($element['#title'])) { 1306 $checkbox = '<label class="option">'. $checkbox .' '. $element['#title'] .'</label>'; 1307 } 1308 1309 unset($element['#title']); 1310 return theme('form_element', $element, $checkbox); 1311 } 1312 1313 /** 1314 * Format a set of checkboxes. 1315 * 1316 * @param $element 1317 * An associative array containing the properties of the element. 1318 * @return 1319 * A themed HTML string representing the checkbox set. 1320 */ 1321 function theme_checkboxes($element) { 1322 $class = 'form-checkboxes'; 1323 if (isset($element['#attributes']['class'])) { 1324 $class .= ' '. $element['#attributes']['class']; 1325 } 1326 $element['#children'] = '<div class="'. $class .'">'. $element['#children'] .'</div>'; 1327 if ($element['#title'] || $element['#description']) { 1328 unset($element['#id']); 1329 return theme('form_element', $element, $element['#children']); 1330 } 1331 else { 1332 return $element['#children']; 1333 } 1334 } 1335 1336 function expand_checkboxes($element) { 1337 $value = is_array($element['#value']) ? $element['#value'] : array(); 1338 $element['#tree'] = TRUE; 1339 if (count($element['#options']) > 0) { 1340 if (!isset($element['#default_value']) || $element['#default_value'] == 0) { 1341 $element['#default_value'] = array(); 1342 } 1343 foreach ($element['#options'] as $key => $choice) { 1344 if (!isset($element[$key])) { 1345 $element[$key] = array('#type' => 'checkbox', '#processed' => TRUE, '#title' => $choice, '#return_value' => $key, '#default_value' => isset($value[$key]), '#attributes' => $element['#attributes']); 1346 } 1347 } 1348 } 1349 return $element; 1350 } 1351 1352 function theme_submit($element) { 1353 return theme('button', $element); 1354 } 1355 1356 function theme_button($element) { 1357 // Make sure not to overwrite classes. 1358 if (isset($element['#attributes']['class'])) { 1359 $element['#attributes']['class'] = 'form-'. $element['#button_type'] .' '. $element['#attributes']['class']; 1360 } 1361 else { 1362 $element['#attributes']['class'] = 'form-'. $element['#button_type']; 1363 } 1364 1365 return '<input type="submit" '. (empty($element['#name']) ? '' : 'name="'. $element['#name'] .'" ') .'id="'. $element['#id'].'" value="'. check_plain($element['#value']) .'" '. drupal_attributes($element['#attributes']) ." />\n"; 1366 } 1367 1368 /** 1369 * Format a hidden form field. 1370 * 1371 * @param $element 1372 * An associative array containing the properties of the element. 1373 * Properties used: value, edit 1374 * @return 1375 * A themed HTML string representing the hidden form field. 1376 */ 1377 function theme_hidden($element) { 1378 return '<input type="hidden" name="'. $element['#name'] . '" id="'. $element['#id'] . '" value="'. check_plain($element['#value']) ."\" " . drupal_attributes($element['#attributes']) ." />\n"; 1379 } 1380 1381 function theme_token($element) { 1382 return theme('hidden', $element); 1383 } 1384 1385 /** 1386 * Format a textfield. 1387 * 1388 * @param $element 1389 * An associative array containing the properties of the element. 1390 * Properties used: title, value, description, size, maxlength, required, attributes autocomplete_path 1391 * @return 1392 * A themed HTML string representing the textfield. 1393 */ 1394 function theme_textfield($element) { 1395 $size = $element['#size'] ? ' size="' . $element['#size'] . '"' : ''; 1396 $class = array('form-text'); 1397 $extra = ''; 1398 $output = ''; 1399 1400 if ($element['#autocomplete_path']) { 1401 drupal_add_js('misc/autocomplete.js'); 1402 $class[] = 'form-autocomplete'; 1403 $extra = '<input class="autocomplete" type="hidden" id="'. $element['#id'] .'-autocomplete" value="'. check_url(url($element['#autocomplete_path'], NULL, NULL, TRUE)) .'" disabled="disabled" />'; 1404 } 1405 _form_set_class($element, $class); 1406 1407 if (isset($element['#field_prefix'])) { 1408 $output .= '<span class="field-prefix">'. $element['#field_prefix'] .'</span> '; 1409 } 1410 1411 $output .= '<input type="text" maxlength="'. $element['#maxlength'] .'" name="'. $element['#name'] .'" id="'. $element['#id'] .'" '. $size .' value="'. check_plain($element['#value']) .'"'. drupal_attributes($element['#attributes']) .' />'; 1412 1413 if (isset($element['#field_suffix'])) { 1414 $output .= ' <span class="field-suffix">'. $element['#field_suffix'] .'</span>'; 1415 } 1416 1417 return theme('form_element', $element, $output). $extra; 1418 } 1419 1420 /** 1421 * Format a form. 1422 * 1423 * @param $element 1424 * An associative array containing the properties of the element. 1425 * Properties used: action, method, attributes, children 1426 * @return 1427 * A themed HTML string representing the form. 1428 */ 1429 function theme_form($element) { 1430 // Anonymous div to satisfy XHTML compliance. 1431 $action = $element['#action'] ? 'action="' . check_url($element['#action']) . '" ' : ''; 1432 return '<form '. $action . ' method="'. $element['#method'] .'" '. 'id="'. $element['#id'] .'"'. drupal_attributes($element['#attributes']) .">\n<div>". $element['#children'] ."\n</div></form>\n"; 1433 } 1434 1435 /** 1436 * Format a textarea. 1437 * 1438 * @param $element 1439 * An associative array containing the properties of the element. 1440 * Properties used: title, value, description, rows, cols, required, attributes 1441 * @return 1442 * A themed HTML string representing the textarea. 1443 */ 1444 function theme_textarea($element) { 1445 $class = array('form-textarea'); 1446 if ($element['#resizable'] !== FALSE) { 1447 drupal_add_js('misc/textarea.js'); 1448 $class[] = 'resizable'; 1449 } 1450 1451 $cols = $element['#cols'] ? ' cols="'. $element['#cols'] .'"' : ''; 1452 _form_set_class($element, $class); 1453 return theme('form_element', $element, '<textarea'. $cols .' rows="'. $element['#rows'] .'" name="'. $element['#name'] .'" id="'. $element['#id'] .'" '. drupal_attributes($element['#attributes']) .'>'. check_plain($element['#value']) .'</textarea>'); 1454 } 1455 1456 /** 1457 * Format HTML markup for use in forms. 1458 * 1459 * This is used in more advanced forms, such as theme selection and filter format. 1460 * 1461 * @param $element 1462 * An associative array containing the properties of the element. 1463 * Properties used: value, children. 1464 * @return 1465 * A themed HTML string representing the HTML markup. 1466 */ 1467 1468 function theme_markup($element) { 1469 return (isset($element['#value']) ? $element['#value'] : '') . (isset($element['#children']) ? $element['#children'] : ''); 1470 } 1471 1472 /** 1473 * Format a password field. 1474 * 1475 * @param $element 1476 * An associative array containing the properties of the element. 1477 * Properties used: title, value, description, size, maxlength, required, attributes 1478 * @return 1479 * A themed HTML string representing the form. 1480 */ 1481 function theme_password($element) { 1482 $size = $element['#size'] ? ' size="'. $element['#size'] .'" ' : ''; 1483 $maxlength = $element['#maxlength'] ? ' maxlength="'. $element['#maxlength'] .'" ' : ''; 1484 1485 _form_set_class($element, array('form-text')); 1486 $output = '<input type="password" name="'. $element['#name'] .'" id="'. $element['#id'] .'" '. $maxlength . $size . drupal_attributes($element['#attributes']) .' />'; 1487 return theme('form_element', $element, $output); 1488 } 1489 1490 /** 1491 * Expand weight elements into selects. 1492 */ 1493 function process_weight($element) { 1494 for ($n = (-1 * $element['#delta']); $n <= $element['#delta']; $n++) { 1495 $weights[$n] = $n; 1496 } 1497 $element['#options'] = $weights; 1498 $element['#type'] = 'select'; 1499 $element['#is_weight'] = TRUE; 1500 return $element; 1501 } 1502 1503 /** 1504 * Format a file upload field. 1505 * 1506 * @param $title 1507 * The label for the file upload field. 1508 * @param $name 1509 * The internal name used to refer to the field. 1510 * @param $size 1511 * A measure of the visible size of the field (passed directly to HTML). 1512 * @param $description 1513 * Explanatory text to display after the form item. 1514 * @param $required 1515 * Whether the user must upload a file to the field. 1516 * @return 1517 * A themed HTML string representing the field. 1518 * 1519 * For assistance with handling the uploaded file correctly, see the API 1520 * provided by file.inc. 1521 */ 1522 function theme_file($element) { 1523 _form_set_class($element, array('form-file')); 1524 return theme('form_element', $element, '<input type="file" name="'. $element['#name'] .'"'. ($element['#attributes'] ? ' '. drupal_attributes($element['#attributes']) : '') .' id="'. $element['#id'] .'" size="'. $element['#size'] ."\" />\n"); 1525 } 1526 1527 /** 1528 * Return a themed form element. 1529 * 1530 * @param element 1531 * An associative array containing the properties of the element. 1532 * Properties used: title, description, id, required 1533 * @param $value 1534 * The form element's data. 1535 * @return 1536 * A string representing the form element. 1537 */ 1538 function theme_form_element($element, $value) { 1539 $output = '<div class="form-item">'."\n"; 1540 $required = !empty($element['#required']) ? '<span class="form-required" title="'. t('This field is required.') .'">*</span>' : ''; 1541 1542 if (!empty($element['#title'])) { 1543 $title = $element['#title']; 1544 if (!empty($element['#id'])) { 1545 $output .= ' <label for="'. $element['#id'] .'">'. t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</label>\n"; 1546 } 1547 else { 1548 $output .= ' <label>'. t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</label>\n"; 1549 } 1550 } 1551 1552 $output .= " $value\n"; 1553 1554 if (!empty($element['#description'])) { 1555 $output .= ' <div class="description">'. $element['#description'] ."</div>\n"; 1556 } 1557 1558 $output .= "</div>\n"; 1559 1560 return $output; 1561 } 1562 1563 /** 1564 * Sets a form element's class attribute. 1565 * 1566 * Adds 'required' and 'error' classes as needed. 1567 * 1568 * @param &$element 1569 * The form element. 1570 * @param $name 1571 * Array of new class names to be added. 1572 */ 1573 function _form_set_class(&$element, $class = array()) { 1574 if ($element['#required']) { 1575 $class[] = 'required'; 1576 } 1577 if (form_get_error($element)){ 1578 $class[] = 'error'; 1579 } 1580 if (isset($element['#attributes']['class'])) { 1581 $class[] = $element['#attributes']['class']; 1582 } 1583 $element['#attributes']['class'] = implode(' ', $class); 1584 } 1585 1586 /** 1587 * Remove invalid characters from an HTML ID attribute string. 1588 * 1589 * @param $id 1590 * The ID to clean. 1591 * @return 1592 * The cleaned ID. 1593 */ 1594 function form_clean_id($id = NULL) { 1595 $id = str_replace(array('][', '_', ' '), '-', $id); 1596 return $id; 1597 } 1598 1599 /** 1600 * @} End of "defgroup form". 1601 */
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Fri Nov 30 16:20:15 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |