2005-10-07 06:11:12 +00:00
< ? php
2005-11-01 09:58:01 +00:00
// $Id$
2005-10-07 06:11:12 +00:00
/**
* @ defgroup form Form generation
* @ {
2006-08-18 18:58:47 +00:00
* Functions to enable the processing and display of HTML forms .
2005-10-07 06:11:12 +00:00
*
2006-08-18 18:58:47 +00:00
* Drupal uses these functions to achieve consistency in its form processing and
* presentation , while simplifying code and reducing the amount of HTML that
* must be explicitly generated by modules .
*
* The drupal_get_form () function handles retrieving , processing , and
* displaying a rendered HTML form for modules automatically . For example :
*
2007-11-09 07:40:55 +00:00
* @ code
2007-01-23 19:17:55 +00:00
* // Display the user registration form.
2006-08-18 18:58:47 +00:00
* $output = drupal_get_form ( 'user_register' );
2007-11-09 07:40:55 +00:00
* @ endcode
2006-08-18 18:58:47 +00:00
*
* Forms can also be built and submitted programmatically without any user input
2006-11-26 22:35:20 +00:00
* using the drupal_execute () function .
2006-08-18 18:58:47 +00:00
*
* For information on the format of the structured arrays used to define forms ,
2007-03-07 17:31:40 +00:00
* and more detailed explanations of the Form API workflow , see the
2007-11-09 07:40:55 +00:00
* @ link http :// api . drupal . org / api / file / developer / topics / forms_api_reference . html reference @ endlink
* and the @ link http :// api . drupal . org / api / file / developer / topics / forms_api . html quickstart guide . @ endlink
2005-10-07 06:11:12 +00:00
*/
/**
2007-05-14 13:43:38 +00:00
* Retrieves a form from a constructor function , or from the cache if
* the form was built in a previous page - load . The form is then passesed
* on for processing , after and rendered for display if necessary .
2005-10-07 06:11:12 +00:00
*
* @ param $form_id
2006-08-18 18:58:47 +00:00
* The unique string identifying the desired form . If a function
* with that name exists , it is called to build the form array .
* Modules that need to generate the same form ( or very similar forms )
* using different $form_ids can implement hook_forms (), which maps
2007-05-14 13:43:38 +00:00
* different $form_id values to the proper form constructor function . Examples
2006-08-18 18:58:47 +00:00
* may be found in node_forms (), search_forms (), and user_forms () .
* @ param ...
2007-10-31 15:10:33 +00:00
* Any additional arguments are passed on to the functions called by
* drupal_get_form (), including the unique form constructor function .
* For example , the node_edit form requires that a node object be passed
* in here when it is called .
2006-08-18 18:58:47 +00:00
* @ return
* The rendered form .
*/
function drupal_get_form ( $form_id ) {
2007-05-14 13:43:38 +00:00
$form_state = array ( 'storage' => NULL , 'submitted' => FALSE );
$args = func_get_args ();
2007-11-19 19:23:28 +00:00
$cacheable = FALSE ;
2007-05-14 13:43:38 +00:00
if ( isset ( $_SESSION [ 'batch_form_state' ])) {
// We've been redirected here after a batch processing : the form has
// already been processed, so we grab the post-process $form_state value
// and move on to form display. See _batch_finished() function.
$form_state = $_SESSION [ 'batch_form_state' ];
unset ( $_SESSION [ 'batch_form_state' ]);
2006-08-25 08:15:24 +00:00
}
else {
2007-05-14 13:43:38 +00:00
// If the incoming $_POST contains a form_build_id, we'll check the
// cache for a copy of the form in question. If it's there, we don't
// have to rebuild the form to proceed. In addition, if there is stored
// form_state data from a previous step, we'll retrieve it so it can
// be passed on to the form processing code.
if ( isset ( $_POST [ 'form_id' ]) && $_POST [ 'form_id' ] == $form_id && ! empty ( $_POST [ 'form_build_id' ])) {
2007-07-29 17:28:23 +00:00
$form = form_get_cache ( $_POST [ 'form_build_id' ], $form_state );
2006-08-25 08:15:24 +00:00
}
2007-05-14 13:43:38 +00:00
// If the previous bit of code didn't result in a populated $form
// object, we're hitting the form for the first time and we need
// to build it from scratch.
if ( ! isset ( $form )) {
2007-05-25 15:39:34 +00:00
$form_state [ 'post' ] = $_POST ;
2007-08-26 07:31:48 +00:00
// Use a copy of the function's arguments for manipulation
$args_temp = $args ;
2007-12-19 22:42:07 +00:00
$args_temp [ 0 ] = & $form_state ;
2007-08-26 07:31:48 +00:00
array_unshift ( $args_temp , $form_id );
2007-06-04 07:22:23 +00:00
2007-08-26 07:31:48 +00:00
$form = call_user_func_array ( 'drupal_retrieve_form' , $args_temp );
2007-05-28 18:53:29 +00:00
$form_build_id = 'form-' . md5 ( mt_rand ());
2006-08-25 08:15:24 +00:00
$form [ '#build_id' ] = $form_build_id ;
2007-05-14 13:43:38 +00:00
drupal_prepare_form ( $form_id , $form , $form_state );
2007-11-19 19:23:28 +00:00
// Store a copy of the unprocessed form for caching and indicate that it
// is cacheable if #cache will be set.
$original_form = $form ;
$cacheable = TRUE ;
2007-05-25 15:39:34 +00:00
unset ( $form_state [ 'post' ]);
2006-08-25 08:15:24 +00:00
}
2007-05-14 13:43:38 +00:00
$form [ '#post' ] = $_POST ;
2006-08-18 18:58:47 +00:00
2007-05-14 13:43:38 +00:00
// Now that we know we have a form, we'll process it (validating,
// submitting, and handling the results returned by its submission
// handlers. Submit handlers accumulate data in the form_state by
// altering the $form_state variable, which is passed into them by
// reference.
drupal_process_form ( $form_id , $form , $form_state );
2007-11-19 19:23:28 +00:00
if ( $cacheable && ! empty ( $form [ '#cache' ])) {
// Caching is done past drupal_process_form so #process callbacks can
// set #cache. By not sending the form state, we avoid storing
// $form_state['storage'].
form_set_cache ( $form_build_id , $original_form , NULL );
}
2007-05-14 13:43:38 +00:00
}
// Most simple, single-step forms will be finished by this point --
// drupal_process_form() usually redirects to another page (or to
// a 'fresh' copy of the form) once processing is complete. If one
// of the form's handlers has set $form_state['redirect'] to FALSE,
// the form will simply be re-rendered with the values still in its
// fields.
//
// If $form_state['storage'] or $form_state['rebuild'] have been
// set by any submit or validate handlers, however, we know that
// we're in a complex multi-part process of some sort and the form's
// workflow is NOT complete. We need to construct a fresh copy of
// the form, passing in the latest $form_state in addition to any
// other variables passed into drupal_get_form().
if ( ! empty ( $form_state [ 'rebuild' ]) || ! empty ( $form_state [ 'storage' ])) {
2007-11-19 19:23:28 +00:00
$form = drupal_rebuild_form ( $form_id , $form_state , $args );
2006-12-06 15:49:45 +00:00
}
2007-05-14 13:43:38 +00:00
// If we haven't redirected to a new location by now, we want to
// render whatever form array is currently in hand.
return drupal_render_form ( $form_id , $form );
}
2006-12-06 15:49:45 +00:00
2007-11-19 19:23:28 +00:00
/**
* Retrieves a form , caches it and processes it with an empty $_POST .
*
* This function clears $_POST and passes the empty $_POST to the form_builder .
* To preserve some parts from $_POST , pass them in $form_state .
*
* If your AHAH callback simulates the pressing of a button , then your AHAH
* callback will need to do the same as what drupal_get_form would do when the
* button is pressed : get the form from the cache , run drupal_process_form over
* it and then if it needs rebuild , run drupal_rebuild_form over it . Then send
* back a part of the returned form .
* $form_state [ 'clicked_button' ][ '#array_parents' ] will help you to find which
* part .
*
* @ param $form_id
* The unique string identifying the desired form . If a function
* with that name exists , it is called to build the form array .
* Modules that need to generate the same form ( or very similar forms )
* using different $form_ids can implement hook_forms (), which maps
* different $form_id values to the proper form constructor function . Examples
* may be found in node_forms (), search_forms (), and user_forms () .
* @ param $form_state
* A keyed array containing the current state of the form . Most
* important is the $form_state [ 'storage' ] collection .
* @ param $args
* Any additional arguments are passed on to the functions called by
* drupal_get_form (), plus the original form_state in the beginning . If you
* are getting a form from the cache , use $form [ '#parameters' ] to shift off
* the $form_id from its beginning then the resulting array can be used as
* $arg here .
* @ param $form_build_id
* If the AHAH callback calling this function only alters part of the form ,
* then pass in the existing form_build_id so we can re - cache with the same
* csid .
* @ return
* The newly built form .
*/
function drupal_rebuild_form ( $form_id , & $form_state , $args , $form_build_id = NULL ) {
// Remove the first argument. This is $form_id.when called from
// drupal_get_form and the original $form_state when called from some AHAH
2007-12-19 22:42:07 +00:00
// callback. Neither is needed. After that, put in the current state.
$args [ 0 ] = & $form_state ;
2007-11-19 19:23:28 +00:00
// And the form_id.
array_unshift ( $args , $form_id );
$form = call_user_func_array ( 'drupal_retrieve_form' , $args );
if ( ! isset ( $form_build_id )) {
// We need a new build_id for the new version of the form.
$form_build_id = 'form-' . md5 ( mt_rand ());
}
$form [ '#build_id' ] = $form_build_id ;
drupal_prepare_form ( $form_id , $form , $form_state );
// Now, we cache the form structure so it can be retrieved later for
// validation. If $form_state['storage'] is populated, we'll also cache
// it so that it can be used to resume complex multi-step processes.
form_set_cache ( $form_build_id , $form , $form_state );
// Clear out all post data, as we don't want the previous step's
// data to pollute this one and trigger validate/submit handling,
// then process the form for rendering.
$_POST = array ();
$form [ '#post' ] = array ();
drupal_process_form ( $form_id , $form , $form_state );
return $form ;
}
2007-07-29 17:28:23 +00:00
/**
* Fetch a form from cache .
*/
function form_get_cache ( $form_build_id , & $form_state ) {
if ( $cached = cache_get ( 'form_' . $form_build_id , 'cache_form' )) {
$form = $cached -> data ;
if ( $cached = cache_get ( 'storage_' . $form_build_id , 'cache_form' )) {
$form_state [ 'storage' ] = $cached -> data ;
}
return $form ;
}
}
/**
* Store a form in the cache
*/
function form_set_cache ( $form_build_id , $form , $form_state ) {
$expire = max ( ini_get ( 'session.cookie_lifetime' ), 86400 );
cache_set ( 'form_' . $form_build_id , $form , 'cache_form' , $expire );
if ( ! empty ( $form_state [ 'storage' ])) {
cache_set ( 'storage_' . $form_build_id , $form_state [ 'storage' ], 'cache_form' , $expire );
}
}
2006-08-31 14:59:28 +00:00
/**
2007-05-14 13:43:38 +00:00
* Retrieves a form using a form_id , populates it with $form_state [ 'values' ],
2006-08-31 14:59:28 +00:00
* processes it , and returns any validation errors encountered . This
* function is the programmatic counterpart to drupal_get_form () .
*
* @ param $form_id
* The unique string identifying the desired form . If a function
* with that name exists , it is called to build the form array .
* Modules that need to generate the same form ( or very similar forms )
* using different $form_ids can implement hook_forms (), which maps
2007-05-14 13:43:38 +00:00
* different $form_id values to the proper form constructor function . Examples
2006-08-31 14:59:28 +00:00
* may be found in node_forms (), search_forms (), and user_forms () .
2007-05-14 13:43:38 +00:00
* @ param $form_state
* A keyed array containing the current state of the form . Most
* important is the $form_state [ 'values' ] collection , a tree of data
* used to simulate the incoming $_POST information from a user ' s
* form submission .
2006-08-31 14:59:28 +00:00
* @ param ...
2007-10-31 15:10:33 +00:00
* Any additional arguments are passed on to the functions called by
* drupal_execute (), including the unique form constructor function .
* For example , the node_edit form requires that a node object be passed
* in here when it is called .
2006-11-26 22:35:20 +00:00
* For example :
*
* // register a new user
2007-05-14 13:43:38 +00:00
* $form_state = array ();
* $form_state [ 'values' ][ 'name' ] = 'robo-user' ;
* $form_state [ 'values' ][ 'mail' ] = 'robouser@example.com' ;
* $form_state [ 'values' ][ 'pass' ] = 'password' ;
2007-09-25 15:14:37 +00:00
* $form_state [ 'values' ][ 'op' ] = t ( 'Create new account' );
2007-05-14 13:43:38 +00:00
* drupal_execute ( 'user_register' , $form_state );
2006-11-26 22:35:20 +00:00
*
* // Create a new node
2007-05-14 13:43:38 +00:00
* $form_state = array ();
2006-11-26 22:35:20 +00:00
* $node = array ( 'type' => 'story' );
2007-05-14 13:43:38 +00:00
* $form_state [ 'values' ][ 'title' ] = 'My node' ;
* $form_state [ 'values' ][ 'body' ] = 'This is the body text!' ;
* $form_state [ 'values' ][ 'name' ] = 'robo-user' ;
2007-09-25 15:14:37 +00:00
* $form_state [ 'values' ][ 'op' ] = t ( 'Save' );
2007-05-14 13:43:38 +00:00
* drupal_execute ( 'story_node_form' , $form_state , $node );
2006-08-31 14:59:28 +00:00
*/
2007-05-14 13:43:38 +00:00
function drupal_execute ( $form_id , & $form_state ) {
2006-08-31 14:59:28 +00:00
$args = func_get_args ();
2007-05-14 13:43:38 +00:00
$form = call_user_func_array ( 'drupal_retrieve_form' , $args );
$form [ '#post' ] = $form_state [ 'values' ];
drupal_prepare_form ( $form_id , $form , $form_state );
drupal_process_form ( $form_id , $form , $form_state );
2006-08-31 14:59:28 +00:00
}
2006-08-18 18:58:47 +00:00
/**
* Retrieves the structured array that defines a given form .
*
* @ param $form_id
* The unique string identifying the desired form . If a function
* with that name exists , it is called to build the form array .
* Modules that need to generate the same form ( or very similar forms )
* using different $form_ids can implement hook_forms (), which maps
2007-05-14 13:43:38 +00:00
* different $form_id values to the proper form constructor function .
2007-06-04 07:22:23 +00:00
* @ param $form_state
* A keyed array containing the current state of the form .
2006-08-18 18:58:47 +00:00
* @ param ...
2007-10-31 15:10:33 +00:00
* Any additional arguments needed by the unique form constructor
* function . Generally , these are any arguments passed into the
* drupal_get_form () or drupal_execute () functions after the first
* argument . If a module implements hook_forms (), it can examine
* these additional arguments and conditionally return different
* builder functions as well .
2006-08-18 18:58:47 +00:00
*/
2007-06-04 07:22:23 +00:00
function drupal_retrieve_form ( $form_id , & $form_state ) {
2006-08-18 18:58:47 +00:00
static $forms ;
2006-10-12 20:36:51 +00:00
// We save two copies of the incoming arguments: one for modules to use
2007-05-14 13:43:38 +00:00
// when mapping form ids to constructor functions, and another to pass to
// the constructor function itself. We shift out the first argument -- the
// $form_id itself -- from the list to pass into the constructor function,
2006-10-12 20:36:51 +00:00
// since it's already known.
2006-08-18 18:58:47 +00:00
$args = func_get_args ();
2006-10-12 20:36:51 +00:00
$saved_args = $args ;
2006-08-18 18:58:47 +00:00
array_shift ( $args );
2007-06-04 07:22:23 +00:00
if ( isset ( $form_state )) {
array_shift ( $args );
}
2006-10-12 20:36:51 +00:00
// We first check to see if there's a function named after the $form_id.
// If there is, we simply pass the arguments on to it to get the form.
2006-08-18 18:58:47 +00:00
if ( ! function_exists ( $form_id )) {
2007-05-14 13:43:38 +00:00
// In cases where many form_ids need to share a central constructor function,
2006-10-12 20:36:51 +00:00
// such as the node editing form, modules can implement hook_forms(). It
2007-05-14 13:43:38 +00:00
// maps one or more form_ids to the correct constructor functions.
2006-10-12 20:36:51 +00:00
//
// We cache the results of that hook to save time, but that only works
// for modules that know all their form_ids in advance. (A module that
// adds a small 'rate this comment' form to each comment in a list
// would need a unique form_id for each one, for example.)
//
// So, we call the hook if $forms isn't yet populated, OR if it doesn't
// yet have an entry for the requested form_id.
if ( ! isset ( $forms ) || ! isset ( $forms [ $form_id ])) {
2007-05-14 13:43:38 +00:00
$forms = module_invoke_all ( 'forms' , $form_id , $args );
2006-08-18 18:58:47 +00:00
}
$form_definition = $forms [ $form_id ];
if ( isset ( $form_definition [ 'callback arguments' ])) {
$args = array_merge ( $form_definition [ 'callback arguments' ], $args );
}
if ( isset ( $form_definition [ 'callback' ])) {
$callback = $form_definition [ 'callback' ];
}
}
2007-06-04 07:22:23 +00:00
2007-12-19 22:42:07 +00:00
array_unshift ( $args , NULL );
$args [ 0 ] = & $form_state ;
2007-06-04 07:22:23 +00:00
2006-10-12 20:36:51 +00:00
// If $callback was returned by a hook_forms() implementation, call it.
// Otherwise, call the function named after the form id.
2006-08-31 14:59:28 +00:00
$form = call_user_func_array ( isset ( $callback ) ? $callback : $form_id , $args );
// We store the original function arguments, rather than the final $arg
// value, so that form_alter functions can see what was originally
// passed to drupal_retrieve_form(). This allows the contents of #parameters
// to be saved and passed in at a later date to recreate the form.
2006-10-12 20:36:51 +00:00
$form [ '#parameters' ] = $saved_args ;
2006-08-31 14:59:28 +00:00
return $form ;
2006-08-18 18:58:47 +00:00
}
/**
* This function is the heart of form API . The form gets built , validated and in
* appropriate cases , submitted .
*
* @ param $form_id
* The unique string identifying the current form .
2005-10-07 06:11:12 +00:00
* @ param $form
* An associative array containing the structure of the form .
2007-05-14 13:43:38 +00:00
* @ param $form_state
* A keyed array containing the current state of the form . This
2007-07-02 14:41:37 +00:00
* includes the current persistent storage data for the form , and
2007-05-14 13:43:38 +00:00
* any data passed along by earlier steps when displaying a
* multi - step form . Additional information , like the sanitized $_POST
* data , is also accumulated here .
2005-10-07 06:11:12 +00:00
*/
2007-05-14 13:43:38 +00:00
function drupal_process_form ( $form_id , & $form , & $form_state ) {
$form_state [ 'values' ] = array ();
$form = form_builder ( $form_id , $form , $form_state );
2007-08-23 18:02:52 +00:00
// Only process the form if it is programmed or the form_id coming
// from the POST data is set and matches the current form_id.
if (( ! empty ( $form [ '#programmed' ])) || ( ! empty ( $form [ '#post' ]) && ( isset ( $form [ '#post' ][ 'form_id' ]) && ( $form [ '#post' ][ 'form_id' ] == $form_id )))) {
2007-05-14 13:43:38 +00:00
drupal_validate_form ( $form_id , $form , $form_state );
2007-10-24 13:35:26 +00:00
// form_clean_id() maintains a cache of element IDs it has seen,
// so it can prevent duplicates. We want to be sure we reset that
// cache when a form is processed, so scenerios that result in
// the form being built behind the scenes and again for the
// browser don't increment all the element IDs needlessly.
form_clean_id ( NULL , TRUE );
2007-05-14 13:43:38 +00:00
if (( ! empty ( $form_state [ 'submitted' ])) && ! form_get_errors () && empty ( $form_state [ 'rebuild' ])) {
$form_state [ 'redirect' ] = NULL ;
form_execute_handlers ( 'submit' , $form , $form_state );
// We'll clear out the cached copies of the form and its stored data
// here, as we've finished with them. The in-memory copies are still
// here, though.
2007-06-17 12:07:51 +00:00
if ( variable_get ( 'cache' , CACHE_DISABLED ) == CACHE_DISABLED && ! empty ( $form_state [ 'values' ][ 'form_build_id' ])) {
2007-05-14 13:43:38 +00:00
cache_clear_all ( 'form_' . $form_state [ 'values' ][ 'form_build_id' ], 'cache_form' );
cache_clear_all ( 'storage_' . $form_state [ 'values' ][ 'form_build_id' ], 'cache_form' );
}
// If batches were set in the submit handlers, we process them now,
2007-09-14 10:40:55 +00:00
// possibly ending execution. We make sure we do not react to the batch
// that is already being processed (if a batch operation performs a
// drupal_execute).
if ( $batch =& batch_get () && ! isset ( $batch [ 'current_set' ])) {
2007-05-14 13:43:38 +00:00
// The batch uses its own copies of $form and $form_state for
// late execution of submit handers and post-batch redirection.
$batch [ 'form' ] = $form ;
$batch [ 'form_state' ] = $form_state ;
2007-05-04 09:41:37 +00:00
$batch [ 'progressive' ] = ! $form [ '#programmed' ];
batch_process ();
2007-05-14 13:43:38 +00:00
// Execution continues only for programmatic forms.
// For 'regular' forms, we get redirected to the batch processing
// page. Form redirection will be handled in _batch_finished(),
// after the batch is processed.
2007-05-04 09:41:37 +00:00
}
2007-05-14 13:43:38 +00:00
// If no submit handlers have populated the $form_state['storage']
// bundle, and the $form_state['rebuild'] flag has not been set,
// we're finished and should redirect to a new destination page
// if one has been set (and a fresh, unpopulated copy of the form
// if one hasn't). If the form was called by drupal_execute(),
// however, we'll skip this and let the calling function examine
// the resulting $form_state bundle itself.
if ( ! $form [ '#programmed' ] && empty ( $form_state [ 'rebuild' ]) && empty ( $form_state [ 'storage' ])) {
2007-12-08 14:06:23 +00:00
drupal_redirect_form ( $form , $form_state [ 'redirect' ]);
2006-08-22 19:12:05 +00:00
}
2006-07-22 19:26:58 +00:00
}
}
}
/**
* Prepares a structured form array by adding required elements ,
* executing any hook_form_alter functions , and optionally inserting
* a validation token to prevent tampering .
*
* @ param $form_id
* A unique string identifying the form for validation , submission ,
* theming , and hook_form_alter functions .
* @ param $form
* An associative array containing the structure of the form .
2007-05-14 13:43:38 +00:00
* @ param $form_state
* A keyed array containing the current state of the form . Passed
* in here so that hook_form_alter () calls can use it , as well .
2006-07-22 19:26:58 +00:00
*/
2007-05-14 13:43:38 +00:00
function drupal_prepare_form ( $form_id , & $form , & $form_state ) {
2006-10-31 08:06:18 +00:00
global $user ;
2005-10-11 19:44:35 +00:00
$form [ '#type' ] = 'form' ;
2007-05-14 13:43:38 +00:00
$form [ '#programmed' ] = isset ( $form [ '#post' ]);
2006-08-18 18:58:47 +00:00
2006-08-25 08:15:24 +00:00
if ( isset ( $form [ '#build_id' ])) {
$form [ 'form_build_id' ] = array (
'#type' => 'hidden' ,
'#value' => $form [ '#build_id' ],
'#id' => $form [ '#build_id' ],
'#name' => 'form_build_id' ,
);
}
2007-01-23 19:17:55 +00:00
// Add a token, based on either #token or form_id, to any form displayed to
// authenticated users. This ensures that any submitted form was actually
// requested previously by the user and protects against cross site request
// forgeries.
2005-10-11 19:44:35 +00:00
if ( isset ( $form [ '#token' ])) {
2006-10-31 08:06:18 +00:00
if ( $form [ '#token' ] === FALSE || $user -> uid == 0 || $form [ '#programmed' ]) {
2006-03-20 16:28:10 +00:00
unset ( $form [ '#token' ]);
2005-11-06 11:38:56 +00:00
}
2006-03-20 16:28:10 +00:00
else {
2006-10-31 08:06:18 +00:00
$form [ 'form_token' ] = array ( '#type' => 'token' , '#default_value' => drupal_get_token ( $form [ '#token' ]));
2006-03-20 16:28:10 +00:00
}
2005-10-07 06:11:12 +00:00
}
2007-03-27 05:13:55 +00:00
else if ( isset ( $user -> uid ) && $user -> uid && ! $form [ '#programmed' ]) {
2006-10-31 08:06:18 +00:00
$form [ '#token' ] = $form_id ;
$form [ 'form_token' ] = array (
2006-12-12 09:39:50 +00:00
'#id' => form_clean_id ( 'edit-' . $form_id . '-form-token' ),
2006-10-31 08:06:18 +00:00
'#type' => 'token' ,
'#default_value' => drupal_get_token ( $form [ '#token' ]),
);
}
2006-02-27 14:46:49 +00:00
if ( isset ( $form_id )) {
2007-05-14 13:43:38 +00:00
$form [ 'form_id' ] = array (
'#type' => 'hidden' ,
'#value' => $form_id ,
'#id' => form_clean_id ( " edit- $form_id " ),
);
2006-02-27 14:46:49 +00:00
}
2006-02-02 02:10:31 +00:00
if ( ! isset ( $form [ '#id' ])) {
2006-12-12 09:39:50 +00:00
$form [ '#id' ] = form_clean_id ( $form_id );
2006-02-02 02:10:31 +00:00
}
2005-10-26 01:24:09 +00:00
2006-03-26 17:41:06 +00:00
$form += _element_info ( 'form' );
2005-10-07 06:11:12 +00:00
2005-11-22 21:31:15 +00:00
if ( ! isset ( $form [ '#validate' ])) {
if ( function_exists ( $form_id . '_validate' )) {
2007-05-14 13:43:38 +00:00
$form [ '#validate' ] = array ( $form_id . '_validate' );
2005-11-22 21:31:15 +00:00
}
}
2005-12-02 15:21:01 +00:00
if ( ! isset ( $form [ '#submit' ])) {
if ( function_exists ( $form_id . '_submit' )) {
2007-01-23 19:17:55 +00:00
// We set submit here so that it can be altered.
2007-05-14 13:43:38 +00:00
$form [ '#submit' ] = array ( $form_id . '_submit' );
2005-11-22 21:31:15 +00:00
}
}
2007-12-18 16:24:01 +00:00
// Normally, we would call drupal_alter($form_id, $form, $form_state).
// However, drupal_alter() normally supports just one byref parameter. Using
// the __drupal_alter_by_ref key, we can store any additional parameters
// that need to be altered, and they'll be split out into additional params
// for the hook_form_alter() implementations.
// @todo: Remove this in Drupal 7.
$data = & $form ;
$data [ '__drupal_alter_by_ref' ] = array ( & $form_state );
drupal_alter ( 'form_' . $form_id , $data );
// __drupal_alter_by_ref is unset in the drupal_alter() function, we need
// to repopulate it to ensure both calls get the data.
$data [ '__drupal_alter_by_ref' ] = array ( & $form_state );
drupal_alter ( 'form' , $data , $form_id );
2005-10-07 06:11:12 +00:00
}
2006-07-22 19:26:58 +00:00
/**
2007-05-14 13:43:38 +00:00
* Validates user - submitted form data from the $form_state using
2006-07-22 19:26:58 +00:00
* the validate functions defined in a structured form array .
*
* @ param $form_id
* A unique string identifying the form for validation , submission ,
* theming , and hook_form_alter functions .
* @ param $form
* An associative array containing the structure of the form .
2007-05-14 13:43:38 +00:00
* @ param $form_state
* A keyed array containing the current state of the form . The current
* user - submitted data is stored in $form_state [ 'values' ], though
* form validation functions are passed an explicit copy of the
* values for the sake of simplicity . Validation handlers can also
* $form_state to pass information on to submit handlers . For example :
* $form_state [ 'data_for_submision' ] = $data ;
* This technique is useful when validation requires file parsing ,
* web service requests , or other expensive requests that should
* not be repeated in the submission step .
2006-07-22 19:26:58 +00:00
*/
2007-05-14 13:43:38 +00:00
function drupal_validate_form ( $form_id , $form , & $form_state ) {
2006-04-07 13:00:37 +00:00
static $validated_forms = array ();
if ( isset ( $validated_forms [ $form_id ])) {
return ;
}
2005-10-07 06:11:12 +00:00
2006-08-18 18:58:47 +00:00
// If the session token was set by drupal_prepare_form(), ensure that it
2007-01-23 19:17:55 +00:00
// matches the current user's session.
2005-10-11 19:44:35 +00:00
if ( isset ( $form [ '#token' ])) {
2007-05-14 13:43:38 +00:00
if ( ! drupal_valid_token ( $form_state [ 'values' ][ 'form_token' ], $form [ '#token' ])) {
2007-01-23 19:17:55 +00:00
// Setting this error will cause the form to fail validation.
2006-05-07 00:08:36 +00:00
form_set_error ( 'form_token' , t ( 'Validation error, please try again. If this error persists, please contact the site administrator.' ));
2005-10-07 06:11:12 +00:00
}
}
2007-05-14 13:43:38 +00:00
_form_validate ( $form , $form_state , $form_id );
2006-04-07 13:00:37 +00:00
$validated_forms [ $form_id ] = TRUE ;
2005-10-07 06:11:12 +00:00
}
2006-07-22 19:26:58 +00:00
/**
* Renders a structured form array into themed HTML .
*
* @ param $form_id
* A unique string identifying the form for validation , submission ,
* theming , and hook_form_alter functions .
* @ param $form
* An associative array containing the structure of the form .
* @ return
* A string containing the path of the page to display when processing
* is complete .
*/
2006-08-18 18:58:47 +00:00
function drupal_render_form ( $form_id , & $form ) {
2006-07-22 19:26:58 +00:00
// Don't override #theme if someone already set it.
if ( ! isset ( $form [ '#theme' ])) {
2007-04-06 13:27:23 +00:00
init_theme ();
$registry = theme_get_registry ();
if ( isset ( $registry [ $form_id ])) {
2006-07-22 19:26:58 +00:00
$form [ '#theme' ] = $form_id ;
}
}
2006-08-10 15:42:33 +00:00
$output = drupal_render ( $form );
2006-07-22 19:26:58 +00:00
return $output ;
}
/**
* Redirect the user to a URL after a form has been processed .
*
* @ param $form
* An associative array containing the structure of the form .
* @ param $redirect
2007-05-14 13:43:38 +00:00
* An optional value containing the destination path to redirect
2006-07-22 19:26:58 +00:00
* to if none is specified by the form .
*/
function drupal_redirect_form ( $form , $redirect = NULL ) {
2007-05-14 13:43:38 +00:00
$goto = NULL ;
2006-07-22 19:26:58 +00:00
if ( isset ( $redirect )) {
$goto = $redirect ;
}
2007-05-14 13:43:38 +00:00
if ( $goto !== FALSE && isset ( $form [ '#redirect' ])) {
2006-07-22 19:26:58 +00:00
$goto = $form [ '#redirect' ];
}
2007-07-01 17:41:16 +00:00
if ( ! isset ( $goto ) || ( $goto !== FALSE )) {
if ( isset ( $goto )) {
if ( is_array ( $goto )) {
call_user_func_array ( 'drupal_goto' , $goto );
}
else {
drupal_goto ( $goto );
}
}
drupal_goto ( $_GET [ 'q' ]);
}
2006-07-22 19:26:58 +00:00
}
2007-01-23 19:17:55 +00:00
/**
* Performs validation on form elements . First ensures required fields are
* completed , #maxlength is not exceeded, and selected options were in the
* list of options given to the user . Then calls user - defined validators .
*
* @ param $elements
* An associative array containing the structure of the form .
2007-05-14 13:43:38 +00:00
* @ param $form_state
* A keyed array containing the current state of the form . The current
* user - submitted data is stored in $form_state [ 'values' ], though
* form validation functions are passed an explicit copy of the
* values for the sake of simplicity . Validation handlers can also
* $form_state to pass information on to submit handlers . For example :
* $form_state [ 'data_for_submision' ] = $data ;
* This technique is useful when validation requires file parsing ,
* web service requests , or other expensive requests that should
* not be repeated in the submission step .
2007-01-23 19:17:55 +00:00
* @ param $form_id
* A unique string identifying the form for validation , submission ,
* theming , and hook_form_alter functions .
*/
2007-05-14 13:43:38 +00:00
function _form_validate ( $elements , & $form_state , $form_id = NULL ) {
2007-11-11 16:14:45 +00:00
// Also used in the installer, pre-database setup.
$t = get_t ();
2007-11-13 14:04:08 +00:00
2006-05-16 10:11:19 +00:00
// Recurse through all children.
foreach ( element_children ( $elements ) as $key ) {
if ( isset ( $elements [ $key ]) && $elements [ $key ]) {
2007-05-14 13:43:38 +00:00
_form_validate ( $elements [ $key ], $form_state );
2006-05-16 10:11:19 +00:00
}
}
2005-10-07 06:11:12 +00:00
/* Validate the current input */
2006-11-16 09:06:59 +00:00
if ( ! isset ( $elements [ '#validated' ]) || ! $elements [ '#validated' ]) {
2006-03-06 14:46:51 +00:00
if ( isset ( $elements [ '#needs_validation' ])) {
2006-03-05 02:46:55 +00:00
// An empty textfield returns '' so we use empty(). An empty checkbox
// and a textfield could return '0' and empty('0') returns TRUE so we
// need a special check for the '0' string.
if ( $elements [ '#required' ] && empty ( $elements [ '#value' ]) && $elements [ '#value' ] !== '0' ) {
2007-11-11 16:14:45 +00:00
form_error ( $elements , $t ( '!name field is required.' , array ( '!name' => $elements [ '#title' ])));
2006-01-06 07:15:47 +00:00
}
2006-03-05 02:46:55 +00:00
2006-12-21 16:16:44 +00:00
// Verify that the value is not longer than #maxlength.
if ( isset ( $elements [ '#maxlength' ]) && drupal_strlen ( $elements [ '#value' ]) > $elements [ '#maxlength' ]) {
2007-11-11 16:14:45 +00:00
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' ]))));
2006-12-21 16:16:44 +00:00
}
2007-10-11 09:22:39 +00:00
if ( isset ( $elements [ '#options' ]) && isset ( $elements [ '#value' ])) {
2006-03-05 02:46:55 +00:00
if ( $elements [ '#type' ] == 'select' ) {
$options = form_options_flatten ( $elements [ '#options' ]);
}
else {
$options = $elements [ '#options' ];
}
if ( is_array ( $elements [ '#value' ])) {
$value = $elements [ '#type' ] == 'checkboxes' ? array_keys ( array_filter ( $elements [ '#value' ])) : $elements [ '#value' ];
foreach ( $value as $v ) {
if ( ! isset ( $options [ $v ])) {
2007-11-11 16:14:45 +00:00
form_error ( $elements , $t ( 'An illegal choice has been detected. Please contact the site administrator.' ));
2007-10-06 15:23:18 +00:00
watchdog ( 'form' , 'Illegal choice %choice in !name element.' , array ( '%choice' => $v , '!name' => empty ( $elements [ '#title' ]) ? $elements [ '#parents' ][ 0 ] : $elements [ '#title' ]), WATCHDOG_ERROR );
2006-03-05 02:46:55 +00:00
}
2005-12-19 14:30:53 +00:00
}
}
2006-03-05 02:46:55 +00:00
elseif ( ! isset ( $options [ $elements [ '#value' ]])) {
2007-11-11 16:14:45 +00:00
form_error ( $elements , $t ( 'An illegal choice has been detected. Please contact the site administrator.' ));
2007-10-15 14:52:18 +00:00
watchdog ( 'form' , 'Illegal choice %choice in %name element.' , array ( '%choice' => $elements [ '#value' ], '%name' => empty ( $elements [ '#title' ]) ? $elements [ '#parents' ][ 0 ] : $elements [ '#title' ]), WATCHDOG_ERROR );
2006-03-05 02:46:55 +00:00
}
2005-12-19 14:30:53 +00:00
}
}
2007-05-14 13:43:38 +00:00
// Call user-defined form level validators.
if ( isset ( $form_id )) {
form_execute_handlers ( 'validate' , $elements , $form_state );
}
// Call any element-specific validators. These must act on the element
// #value data.
elseif ( isset ( $elements [ '#element_validate' ])) {
foreach ( $elements [ '#element_validate' ] as $function ) {
2005-12-03 09:44:50 +00:00
if ( function_exists ( $function )) {
2007-05-14 13:43:38 +00:00
$function ( $elements , $form_state );
2005-10-07 06:11:12 +00:00
}
}
}
2005-10-11 19:44:35 +00:00
$elements [ '#validated' ] = TRUE ;
2005-10-07 06:11:12 +00:00
}
}
2007-05-14 13:43:38 +00:00
/**
* A helper function used to execute custom validation and submission
* handlers for a given form . Button - specific handlers are checked
* first . If none exist , the function falls back to form - level handlers .
*
* @ param $type
* The type of handler to execute . 'validate' or 'submit' are the
* defaults used by Form API .
* @ param $form
* An associative array containing the structure of the form .
* @ param $form_state
* A keyed array containing the current state of the form . If the user
* submitted the form by clicking a button with custom handler functions
* defined , those handlers will be stored here .
*/
function form_execute_handlers ( $type , & $form , & $form_state ) {
$return = FALSE ;
if ( isset ( $form_state [ $type . '_handlers' ])) {
$handlers = $form_state [ $type . '_handlers' ];
}
elseif ( isset ( $form [ '#' . $type ])) {
$handlers = $form [ '#' . $type ];
}
else {
$handlers = array ();
}
foreach ( $handlers as $function ) {
if ( function_exists ( $function )) {
if ( $type == 'submit' && ( $batch =& batch_get ())) {
// Some previous _submit handler has set a batch. We store the call
// in a special 'control' batch set, for execution at the correct
// time during the batch processing workflow.
2007-05-16 07:56:19 +00:00
$batch [ 'sets' ][] = array ( 'form_submit' => $function );
2007-05-14 13:43:38 +00:00
}
else {
2007-06-04 07:22:23 +00:00
$function ( $form , $form_state );
2007-05-14 13:43:38 +00:00
}
$return = TRUE ;
}
}
return $return ;
}
2005-10-13 10:02:31 +00:00
/**
* File an error against a form element . If the name of the element is
* edit [ foo ][ bar ] then you may pass either foo or foo ][ bar as $name
* foo will set an error for all its children .
*/
2006-01-24 10:15:03 +00:00
function form_set_error ( $name = NULL , $message = '' ) {
2005-10-13 10:02:31 +00:00
static $form = array ();
if ( isset ( $name ) && ! isset ( $form [ $name ])) {
$form [ $name ] = $message ;
2006-01-24 10:15:03 +00:00
if ( $message ) {
drupal_set_message ( $message , 'error' );
}
2005-10-13 10:02:31 +00:00
}
return $form ;
}
/**
* Return an associative array of all errors .
*/
function form_get_errors () {
$form = form_set_error ();
if ( ! empty ( $form )) {
return $form ;
}
}
/**
* Return the error message filed against the form with the specified name .
*/
function form_get_error ( $element ) {
$form = form_set_error ();
$key = $element [ '#parents' ][ 0 ];
if ( isset ( $form [ $key ])) {
return $form [ $key ];
}
$key = implode ( '][' , $element [ '#parents' ]);
if ( isset ( $form [ $key ])) {
return $form [ $key ];
}
}
2005-10-07 06:11:12 +00:00
/**
* Flag an element as having an error .
*/
2006-01-24 10:15:03 +00:00
function form_error ( & $element , $message = '' ) {
2005-10-13 10:02:31 +00:00
form_set_error ( implode ( '][' , $element [ '#parents' ]), $message );
2005-10-07 06:11:12 +00:00
}
/**
2007-05-14 13:43:38 +00:00
* Walk through the structured form array , adding any required
* properties to each element and mapping the incoming $_POST
* data to the proper elements .
2006-02-17 10:51:57 +00:00
*
* @ param $form_id
2006-07-22 19:26:58 +00:00
* A unique string identifying the form for validation , submission ,
* theming , and hook_form_alter functions .
2006-02-17 10:51:57 +00:00
* @ param $form
* An associative array containing the structure of the form .
2007-05-14 13:43:38 +00:00
* @ param $form_state
* A keyed array containing the current state of the form . In this
* context , it is used to accumulate information about which button
* was clicked when the form was submitted , as well as the sanitized
* $_POST data .
2005-10-07 06:11:12 +00:00
*/
2007-05-14 13:43:38 +00:00
function form_builder ( $form_id , $form , & $form_state ) {
2007-11-19 19:23:28 +00:00
static $complete_form , $cache ;
2007-10-16 14:06:23 +00:00
2006-06-23 08:31:23 +00:00
// Initialize as unprocessed.
$form [ '#processed' ] = FALSE ;
2005-10-07 06:11:12 +00:00
/* Use element defaults */
2005-10-11 19:44:35 +00:00
if (( ! empty ( $form [ '#type' ])) && ( $info = _element_info ( $form [ '#type' ]))) {
2007-01-23 19:17:55 +00:00
// Overlay $info onto $form, retaining preexisting keys in $form.
2005-10-07 06:11:12 +00:00
$form += $info ;
}
2007-10-16 14:06:23 +00:00
if ( isset ( $form [ '#type' ]) && $form [ '#type' ] == 'form' ) {
$complete_form = $form ;
if ( ! empty ( $form [ '#programmed' ])) {
$form_state [ 'submitted' ] = TRUE ;
}
2007-06-17 12:07:51 +00:00
}
2006-01-24 08:20:45 +00:00
if ( isset ( $form [ '#input' ]) && $form [ '#input' ]) {
2007-10-16 14:06:23 +00:00
_form_builder_handle_input_element ( $form_id , $form , $form_state , $complete_form );
2005-12-19 14:43:42 +00:00
}
2007-06-28 07:48:41 +00:00
$form [ '#defaults_loaded' ] = TRUE ;
2005-12-19 14:43:42 +00:00
2007-01-10 23:30:07 +00:00
// We start off assuming all form elements are in the correct order.
$form [ '#sorted' ] = TRUE ;
2005-10-07 06:11:12 +00:00
// Recurse through all child elements.
2007-01-10 23:30:07 +00:00
$count = 0 ;
2005-10-07 06:11:12 +00:00
foreach ( element_children ( $form ) as $key ) {
2006-08-18 18:58:47 +00:00
$form [ $key ][ '#post' ] = $form [ '#post' ];
$form [ $key ][ '#programmed' ] = $form [ '#programmed' ];
2007-01-23 19:17:55 +00:00
// Don't squash an existing tree value.
2005-11-18 13:48:09 +00:00
if ( ! isset ( $form [ $key ][ '#tree' ])) {
$form [ $key ][ '#tree' ] = $form [ '#tree' ];
}
2005-10-26 01:24:09 +00:00
2007-01-23 19:17:55 +00:00
// Deny access to child elements if parent is denied.
2006-08-22 11:13:04 +00:00
if ( isset ( $form [ '#access' ]) && ! $form [ '#access' ]) {
$form [ $key ][ '#access' ] = FALSE ;
}
2007-01-23 19:17:55 +00:00
// Don't squash existing parents value.
2005-11-18 13:48:09 +00:00
if ( ! isset ( $form [ $key ][ '#parents' ])) {
2007-01-23 19:17:55 +00:00
// Check to see if a tree of child elements is present. If so,
// continue down the tree if required.
2005-12-04 08:14:07 +00:00
$form [ $key ][ '#parents' ] = $form [ $key ][ '#tree' ] && $form [ '#tree' ] ? array_merge ( $form [ '#parents' ], array ( $key )) : array ( $key );
2007-11-19 19:23:28 +00:00
$array_parents = isset ( $form [ '#array_parents' ]) ? $form [ '#array_parents' ] : array ();
$array_parents [] = $key ;
$form [ $key ][ '#array_parents' ] = $array_parents ;
2005-10-26 01:24:09 +00:00
}
2007-01-23 19:17:55 +00:00
// Assign a decimal placeholder weight to preserve original array order.
2005-11-18 13:48:09 +00:00
if ( ! isset ( $form [ $key ][ '#weight' ])) {
$form [ $key ][ '#weight' ] = $count / 1000 ;
}
2007-01-10 23:30:07 +00:00
else {
2007-01-23 19:17:55 +00:00
// If one of the child elements has a weight then we will need to sort
// later.
2007-01-10 23:30:07 +00:00
unset ( $form [ '#sorted' ]);
}
2007-05-14 13:43:38 +00:00
$form [ $key ] = form_builder ( $form_id , $form [ $key ], $form_state );
2005-10-07 06:11:12 +00:00
$count ++ ;
}
2007-05-14 13:43:38 +00:00
// The #after_build flag allows any piece of a form to be altered
// after normal input parsing has been completed.
2006-04-20 07:11:37 +00:00
if ( isset ( $form [ '#after_build' ]) && ! isset ( $form [ '#after_build_done' ])) {
foreach ( $form [ '#after_build' ] as $function ) {
2007-06-04 07:22:23 +00:00
$form = $function ( $form , $form_state );
2007-05-14 13:43:38 +00:00
$form [ '#after_build_done' ] = TRUE ;
}
}
// Now that we've processed everything, we can go back to handle the funky
2007-07-02 14:41:37 +00:00
// Internet Explorer button-click scenario.
2007-05-14 13:43:38 +00:00
_form_builder_ie_cleanup ( $form , $form_state );
2007-07-03 19:13:49 +00:00
// After handling the special IE case, we no longer need the buttons collection.
unset ( $form_state [ 'buttons' ]);
2007-11-19 19:23:28 +00:00
// If some callback set #cache, we need to flip a static flag so later it
// can be found.
if ( isset ( $form [ '#cache' ])) {
$cache = $form [ '#cache' ];
}
// We are on the top form, we can copy back #cache if it's set.
if ( isset ( $form [ '#type' ]) && $form [ '#type' ] == 'form' && isset ( $cache )) {
$form [ '#cache' ] = TRUE ;
}
2007-05-14 13:43:38 +00:00
return $form ;
}
/**
* Populate the #value and #name properties of input elements so they
* can be processed and rendered . Also , execute any #process handlers
* attached to a specific element .
*/
2007-10-16 14:06:23 +00:00
function _form_builder_handle_input_element ( $form_id , & $form , & $form_state , $complete_form ) {
2007-05-14 13:43:38 +00:00
if ( ! isset ( $form [ '#name' ])) {
$name = array_shift ( $form [ '#parents' ]);
$form [ '#name' ] = $name ;
if ( $form [ '#type' ] == 'file' ) {
// To make it easier to handle $_FILES in file.inc, we place all
// file fields in the 'files' array. Also, we do not support
// nested file names.
$form [ '#name' ] = 'files[' . $form [ '#name' ] . ']' ;
}
elseif ( count ( $form [ '#parents' ])) {
$form [ '#name' ] .= '[' . implode ( '][' , $form [ '#parents' ]) . ']' ;
}
array_unshift ( $form [ '#parents' ], $name );
}
if ( ! isset ( $form [ '#id' ])) {
$form [ '#id' ] = form_clean_id ( 'edit-' . implode ( '-' , $form [ '#parents' ]));
}
2007-07-04 15:45:37 +00:00
unset ( $edit );
2007-05-14 13:43:38 +00:00
if ( ! empty ( $form [ '#disabled' ])) {
$form [ '#attributes' ][ 'disabled' ] = 'disabled' ;
}
if ( ! isset ( $form [ '#value' ]) && ! array_key_exists ( '#value' , $form )) {
2007-07-14 15:23:29 +00:00
$function = ! empty ( $form [ '#value_callback' ]) ? $form [ '#value_callback' ] : 'form_type_' . $form [ '#type' ] . '_value' ;
2007-05-14 13:43:38 +00:00
if (( $form [ '#programmed' ]) || (( ! isset ( $form [ '#access' ]) || $form [ '#access' ]) && isset ( $form [ '#post' ]) && ( isset ( $form [ '#post' ][ 'form_id' ]) && $form [ '#post' ][ 'form_id' ] == $form_id ))) {
$edit = $form [ '#post' ];
foreach ( $form [ '#parents' ] as $parent ) {
$edit = isset ( $edit [ $parent ]) ? $edit [ $parent ] : NULL ;
}
if ( ! $form [ '#programmed' ] || isset ( $edit )) {
2007-07-04 15:45:37 +00:00
// Call #type_value to set the form value;
if ( function_exists ( $function )) {
$form [ '#value' ] = $function ( $form , $edit );
2007-05-14 13:43:38 +00:00
}
2007-07-04 15:45:37 +00:00
if ( ! isset ( $form [ '#value' ]) && isset ( $edit )) {
$form [ '#value' ] = $edit ;
2007-05-14 13:43:38 +00:00
}
}
2007-07-04 15:45:37 +00:00
// Mark all posted values for validation.
if ( isset ( $form [ '#value' ]) || ( isset ( $form [ '#required' ]) && $form [ '#required' ])) {
$form [ '#needs_validation' ] = TRUE ;
}
2007-05-14 13:43:38 +00:00
}
2007-07-04 15:45:37 +00:00
// Load defaults.
2007-05-14 13:43:38 +00:00
if ( ! isset ( $form [ '#value' ])) {
2007-07-04 15:45:37 +00:00
// Call #type_value without a second argument to request default_value handling.
2006-04-20 07:11:37 +00:00
if ( function_exists ( $function )) {
2007-07-04 15:45:37 +00:00
$form [ '#value' ] = $function ( $form );
2007-05-14 13:43:38 +00:00
}
2007-07-04 15:45:37 +00:00
// Final catch. If we haven't set a value yet, use the explicit default value.
2007-09-04 21:10:45 +00:00
if ( ! isset ( $form [ '#value' ])) {
2007-05-14 13:43:38 +00:00
$form [ '#value' ] = isset ( $form [ '#default_value' ]) ? $form [ '#default_value' ] : '' ;
2006-04-20 07:11:37 +00:00
}
}
2005-10-26 01:24:09 +00:00
}
2006-04-06 15:30:19 +00:00
2007-05-14 13:43:38 +00:00
// Determine which button (if any) was clicked to submit the form.
// We compare the incoming values with the buttons defined in the form,
// and flag the one that matches. We have to do some funky tricks to
// deal with Internet Explorer's handling of single-button forms, though.
if ( ! empty ( $form [ '#post' ]) && isset ( $form [ '#executes_submit_callback' ])) {
// First, accumulate a collection of buttons, divided into two bins:
// those that execute full submit callbacks and those that only validate.
$button_type = $form [ '#executes_submit_callback' ] ? 'submit' : 'button' ;
$form_state [ 'buttons' ][ $button_type ][] = $form ;
2007-07-29 17:28:23 +00:00
if ( _form_button_was_clicked ( $form )) {
2007-05-14 13:43:38 +00:00
$form_state [ 'submitted' ] = $form_state [ 'submitted' ] || $form [ '#executes_submit_callback' ];
// In most cases, we want to use form_set_value() to manipulate
// the global variables. In this special case, we want to make sure that
// the value of this element is listed in $form_variables under 'op'.
$form_state [ 'values' ][ $form [ '#name' ]] = $form [ '#value' ];
2007-07-03 19:13:49 +00:00
$form_state [ 'clicked_button' ] = $form ;
2007-05-14 13:43:38 +00:00
if ( isset ( $form [ '#validate' ])) {
$form_state [ 'validate_handlers' ] = $form [ '#validate' ];
}
if ( isset ( $form [ '#submit' ])) {
$form_state [ 'submit_handlers' ] = $form [ '#submit' ];
}
}
}
// Allow for elements to expand to multiple elements, e.g., radios,
// checkboxes and files.
if ( isset ( $form [ '#process' ]) && ! $form [ '#processed' ]) {
foreach ( $form [ '#process' ] as $process ) {
if ( function_exists ( $process )) {
2007-11-19 19:23:28 +00:00
$form = $process ( $form , isset ( $edit ) ? $edit : NULL , $form_state , $complete_form );
2007-05-14 13:43:38 +00:00
}
}
$form [ '#processed' ] = TRUE ;
}
form_set_value ( $form , $form [ '#value' ], $form_state );
}
2007-07-29 17:28:23 +00:00
/**
* Helper function to handle the sometimes - convoluted logic of button
* click detection .
*
* In Internet Explorer , if ONLY one submit button is present , AND the
* enter key is used to submit the form , no form value is sent for it
* and we ' ll never detect a match . That special case is handled by
* _form_builder_ie_cleanup () .
*/
function _form_button_was_clicked ( $form ) {
// First detect normal 'vanilla' button clicks. Traditionally, all
// standard buttons on a form share the same name (usually 'op'),
// and the specific return value is used to determine which was
// clicked. This ONLY works as long as $form['#name'] puts the
// value at the top level of the tree of $_POST data.
if ( isset ( $form [ '#post' ][ $form [ '#name' ]]) && $form [ '#post' ][ $form [ '#name' ]] == $form [ '#value' ]) {
return TRUE ;
}
// When image buttons are clicked, browsers do NOT pass the form element
// value in $_POST. Instead they pass an integer representing the
// coordinates of the click on the button image. This means that image
// buttons MUST have unique $form['#name'] values, but the details of
// their $_POST data should be ignored.
elseif ( ! empty ( $form [ '#has_garbage_value' ]) && isset ( $form [ '#value' ]) && $form [ '#value' ] !== '' ) {
return TRUE ;
}
return FALSE ;
}
/**
* In IE , if only one submit button is present , AND the enter key is
* used to submit the form , no form value is sent for it and our normal
* button detection code will never detect a match . We call this
* function after all other button - detection is complete to check
* for the proper conditions , and treat the single button on the form
* as 'clicked' if they are met .
*/
function _form_builder_ie_cleanup ( $form , & $form_state ) {
// Quick check to make sure we're always looking at the full form
// and not a sub-element.
if ( ! empty ( $form [ '#type' ]) && $form [ '#type' ] == 'form' ) {
// If we haven't recognized a submission yet, and there's a single
// submit button, we know that we've hit the right conditions. Grab
// the first one and treat it as the clicked button.
if ( empty ( $form_state [ 'submitted' ]) && ! empty ( $form_state [ 'buttons' ][ 'submit' ]) && empty ( $form_state [ 'buttons' ][ 'button' ])) {
$button = $form_state [ 'buttons' ][ 'submit' ][ 0 ];
// Set up all the $form_state information that would have been
// populated had the button been recognized earlier.
$form_state [ 'submitted' ] = TRUE ;
$form_state [ 'submit_handlers' ] = empty ( $button [ '#submit' ]) ? NULL : $button [ '#submit' ];
$form_state [ 'validate_handlers' ] = empty ( $button [ '#validate' ]) ? NULL : $button [ '#validate' ];
$form_state [ 'values' ][ $button [ '#name' ]] = $button [ '#value' ];
$form_state [ 'clicked_button' ] = $button ;
}
}
}
2007-08-10 10:51:17 +00:00
/**
* Helper function to determine the value for an image button form element .
*
* @ param $form
* The form element whose value is being populated .
* @ param $edit
* The incoming POST data to populate the form element . If this is FALSE ,
* the element ' s default value should be returned .
* @ return
* The data that will appear in the $form_state [ 'values' ] collection
* for this element . Return nothing to use the default .
*/
function form_type_image_button_value ( $form , $edit = FALSE ) {
if ( $edit !== FALSE ) {
if ( ! empty ( $edit )) {
// If we're dealing with Mozilla or Opera, we're lucky. It will
// return a proper value, and we can get on with things.
return $form [ '#return_value' ];
}
else {
// Unfortunately, in IE we never get back a proper value for THIS
// form element. Instead, we get back two split values: one for the
// X and one for the Y coordinates on which the user clicked the
// button. We'll find this element in the #post data, and search
// in the same spot for its name, with '_x'.
$post = $form [ '#post' ];
foreach ( split ( '\[' , $form [ '#name' ]) as $element_name ) {
// chop off the ] that may exist.
if ( substr ( $element_name , - 1 ) == ']' ) {
$element_name = substr ( $element_name , 0 , - 1 );
}
if ( ! isset ( $post [ $element_name ])) {
if ( isset ( $post [ $element_name . '_x' ])) {
return $form [ '#return_value' ];
}
return NULL ;
}
$post = $array [ $element_name ];
}
return $form [ '#return_value' ];
}
}
}
2007-07-04 15:45:37 +00:00
/**
* Helper function to determine the value for a checkbox form element .
*
* @ param $form
2007-07-14 15:23:29 +00:00
* The form element whose value is being populated .
2007-07-04 15:45:37 +00:00
* @ param $edit
2007-07-14 15:23:29 +00:00
* The incoming POST data to populate the form element . If this is FALSE ,
* the element ' s default value should be returned .
2007-07-04 15:45:37 +00:00
* @ return
2007-07-14 15:23:29 +00:00
* The data that will appear in the $form_state [ 'values' ] collection
* for this element . Return nothing to use the default .
2007-07-04 15:45:37 +00:00
*/
2007-07-14 15:23:29 +00:00
function form_type_checkbox_value ( $form , $edit = FALSE ) {
if ( $edit !== FALSE ) {
2007-07-04 15:45:37 +00:00
return ! empty ( $edit ) ? $form [ '#return_value' ] : 0 ;
}
}
/**
* Helper function to determine the value for a checkboxes form element .
*
* @ param $form
2007-07-14 15:23:29 +00:00
* The form element whose value is being populated .
2007-07-04 15:45:37 +00:00
* @ param $edit
2007-07-14 15:23:29 +00:00
* The incoming POST data to populate the form element . If this is FALSE ,
* the element ' s default value should be returned .
2007-07-04 15:45:37 +00:00
* @ return
2007-07-14 15:23:29 +00:00
* The data that will appear in the $form_state [ 'values' ] collection
* for this element . Return nothing to use the default .
2007-07-04 15:45:37 +00:00
*/
2007-09-25 11:29:10 +00:00
function form_type_checkboxes_value ( $form , $edit = FALSE ) {
2007-07-14 15:23:29 +00:00
if ( $edit === FALSE ) {
2007-07-04 15:45:37 +00:00
$value = array ();
$form += array ( '#default_value' => array ());
foreach ( $form [ '#default_value' ] as $key ) {
$value [ $key ] = 1 ;
}
return $value ;
}
2007-09-25 11:29:10 +00:00
elseif ( ! isset ( $edit )) {
return array ();
}
2007-07-04 15:45:37 +00:00
}
/**
* Helper function to determine the value for a password_confirm form
* element .
*
* @ param $form
2007-07-14 15:23:29 +00:00
* The form element whose value is being populated .
2007-07-04 15:45:37 +00:00
* @ param $edit
2007-07-14 15:23:29 +00:00
* The incoming POST data to populate the form element . If this is FALSE ,
* the element ' s default value should be returned .
2007-07-04 15:45:37 +00:00
* @ return
2007-07-14 15:23:29 +00:00
* The data that will appear in the $form_state [ 'values' ] collection
* for this element . Return nothing to use the default .
2007-07-04 15:45:37 +00:00
*/
2007-07-14 15:23:29 +00:00
function form_type_password_confirm_value ( $form , $edit = FALSE ) {
if ( $edit === FALSE ) {
2007-07-04 15:45:37 +00:00
$form += array ( '#default_value' => array ());
return $form [ '#default_value' ] + array ( 'pass1' => '' , 'pass2' => '' );
}
}
/**
* Helper function to determine the value for a select form element .
*
* @ param $form
2007-07-14 15:23:29 +00:00
* The form element whose value is being populated .
2007-07-04 15:45:37 +00:00
* @ param $edit
2007-07-14 15:23:29 +00:00
* The incoming POST data to populate the form element . If this is FALSE ,
* the element ' s default value should be returned .
2007-07-04 15:45:37 +00:00
* @ return
2007-07-14 15:23:29 +00:00
* The data that will appear in the $form_state [ 'values' ] collection
* for this element . Return nothing to use the default .
2007-07-04 15:45:37 +00:00
*/
2007-07-14 15:23:29 +00:00
function form_type_select_value ( $form , $edit = FALSE ) {
if ( $edit !== FALSE ) {
2007-07-04 15:45:37 +00:00
if ( isset ( $form [ '#multiple' ]) && $form [ '#multiple' ]) {
return ( is_array ( $edit )) ? drupal_map_assoc ( $edit ) : array ();
}
else {
return $edit ;
}
}
}
/**
* Helper function to determine the value for a textfield form element .
*
* @ param $form
2007-07-14 15:23:29 +00:00
* The form element whose value is being populated .
2007-07-04 15:45:37 +00:00
* @ param $edit
2007-07-14 15:23:29 +00:00
* The incoming POST data to populate the form element . If this is FALSE ,
* the element ' s default value should be returned .
2007-07-04 15:45:37 +00:00
* @ return
2007-07-14 15:23:29 +00:00
* The data that will appear in the $form_state [ 'values' ] collection
* for this element . Return nothing to use the default .
2007-07-04 15:45:37 +00:00
*/
2007-07-14 15:23:29 +00:00
function form_type_textfield_value ( $form , $edit = FALSE ) {
if ( $edit !== FALSE ) {
2007-07-04 15:45:37 +00:00
// Equate $edit to the form value to ensure it's marked for
// validation.
return str_replace ( array ( " \r " , " \n " ), '' , $edit );
}
}
/**
* Helper function to determine the value for form ' s token value .
*
* @ param $form
2007-07-14 15:23:29 +00:00
* The form element whose value is being populated .
2007-07-04 15:45:37 +00:00
* @ param $edit
2007-07-14 15:23:29 +00:00
* The incoming POST data to populate the form element . If this is FALSE ,
* the element ' s default value should be returned .
2007-07-04 15:45:37 +00:00
* @ return
2007-07-14 15:23:29 +00:00
* The data that will appear in the $form_state [ 'values' ] collection
* for this element . Return nothing to use the default .
2007-07-04 15:45:37 +00:00
*/
2007-07-14 15:23:29 +00:00
function form_type_token_value ( $form , $edit = FALSE ) {
if ( $edit !== FALSE ) {
2007-07-04 15:45:37 +00:00
return ( string ) $edit ;
}
}
2006-04-15 21:52:44 +00:00
/**
2006-04-17 20:48:26 +00:00
* Use this function to make changes to form values in the form validate
2007-05-14 13:43:38 +00:00
* phase , so they will be available in the submit phase in $form_state .
2006-04-15 21:52:44 +00:00
*
* Specifically , if $form [ '#parents' ] is array ( 'foo' , 'bar' )
* and $value is 'baz' then this function will make
2007-06-04 07:22:23 +00:00
* $form_state [ 'values' ][ 'foo' ][ 'bar' ] to be 'baz' .
2006-04-15 21:52:44 +00:00
*
* @ param $form
* The form item . Keys used : #parents, #value
* @ param $value
* The value for the form item .
*/
2007-05-14 13:43:38 +00:00
function form_set_value ( $form , $value , & $form_state ) {
_form_set_value ( $form_state [ 'values' ], $form , $form [ '#parents' ], $value );
2006-04-15 21:52:44 +00:00
}
/**
* Helper function for form_set_value () .
*
2007-01-23 19:17:55 +00:00
* We iterate over $parents and create nested arrays for them
2007-06-04 07:22:23 +00:00
* in $form_state [ 'values' ] if needed . Then we insert the value into
2006-04-15 21:52:44 +00:00
* the right array .
*/
function _form_set_value ( & $form_values , $form , $parents , $value ) {
$parent = array_shift ( $parents );
if ( empty ( $parents )) {
$form_values [ $parent ] = $value ;
}
else {
if ( ! isset ( $form_values [ $parent ])) {
$form_values [ $parent ] = array ();
}
_form_set_value ( $form_values [ $parent ], $form , $parents , $value );
}
}
2005-10-07 06:11:12 +00:00
/**
* Retrieve the default properties for the defined element type .
*/
2006-07-05 11:45:51 +00:00
function _element_info ( $type , $refresh = NULL ) {
2005-10-07 06:11:12 +00:00
static $cache ;
2005-10-26 01:24:09 +00:00
2005-10-07 06:11:12 +00:00
$basic_defaults = array (
2005-10-11 19:44:35 +00:00
'#description' => NULL ,
'#attributes' => array (),
'#required' => FALSE ,
2005-10-26 01:24:09 +00:00
'#tree' => FALSE ,
2006-01-15 16:55:35 +00:00
'#parents' => array ()
2005-10-07 06:11:12 +00:00
);
2006-01-15 16:55:35 +00:00
if ( ! isset ( $cache ) || $refresh ) {
2005-10-07 06:11:12 +00:00
$cache = array ();
foreach ( module_implements ( 'elements' ) as $module ) {
$elements = module_invoke ( $module , 'elements' );
2005-12-14 20:10:45 +00:00
if ( isset ( $elements ) && is_array ( $elements )) {
2005-11-28 16:37:11 +00:00
$cache = array_merge_recursive ( $cache , $elements );
2005-10-07 06:11:12 +00:00
}
}
if ( sizeof ( $cache )) {
foreach ( $cache as $element_type => $info ) {
2005-11-28 16:37:11 +00:00
$cache [ $element_type ] = array_merge_recursive ( $basic_defaults , $info );
2005-10-07 06:11:12 +00:00
}
}
}
return $cache [ $type ];
}
2006-01-06 07:15:47 +00:00
function form_options_flatten ( $array , $reset = TRUE ) {
static $return ;
if ( $reset ) {
$return = array ();
}
foreach ( $array as $key => $value ) {
2006-10-31 07:37:25 +00:00
if ( is_object ( $value )) {
form_options_flatten ( $value -> option , FALSE );
}
else if ( is_array ( $value )) {
2006-01-06 07:15:47 +00:00
form_options_flatten ( $value , FALSE );
}
else {
$return [ $key ] = 1 ;
}
}
return $return ;
}
2005-10-07 06:11:12 +00:00
/**
* Format a dropdown menu or scrolling selection box .
*
* @ param $element
* An associative array containing the properties of the element .
2006-01-18 19:04:12 +00:00
* Properties used : title , value , options , description , extra , multiple , required
2005-10-07 06:11:12 +00:00
* @ return
* A themed HTML string representing the form element .
*
2007-12-06 09:58:34 +00:00
* @ ingroup themeable
*
2005-10-07 06:11:12 +00:00
* It is possible to group options together ; to do this , change the format of
* $options to an associative array in which the keys are group labels , and the
* values are associative arrays in the normal $options format .
*/
function theme_select ( $element ) {
$select = '' ;
2007-04-13 08:56:59 +00:00
$size = $element [ '#size' ] ? ' size="' . $element [ '#size' ] . '"' : '' ;
2006-04-07 13:22:12 +00:00
_form_set_class ( $element , array ( 'form-select' ));
2007-01-31 15:49:26 +00:00
$multiple = $element [ '#multiple' ];
2006-05-02 09:26:33 +00:00
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>' );
2006-01-19 09:22:16 +00:00
}
function form_select_options ( $element , $choices = NULL ) {
if ( ! isset ( $choices )) {
$choices = $element [ '#options' ];
}
2006-04-11 11:33:15 +00:00
// array_key_exists() accommodates the rare event where $element['#value'] is NULL.
2006-01-13 07:44:59 +00:00
// isset() fails in this situation.
$value_valid = isset ( $element [ '#value' ]) || array_key_exists ( '#value' , $element );
$value_is_array = is_array ( $element [ '#value' ]);
2006-01-19 09:22:16 +00:00
$options = '' ;
foreach ( $choices as $key => $choice ) {
2005-10-07 06:11:12 +00:00
if ( is_array ( $choice )) {
2006-01-19 09:22:16 +00:00
$options .= '<optgroup label="' . $key . '">' ;
$options .= form_select_options ( $element , $choice );
$options .= '</optgroup>' ;
2005-10-07 06:11:12 +00:00
}
2006-10-20 20:55:03 +00:00
elseif ( is_object ( $choice )) {
$options .= form_select_options ( $element , $choice -> option );
}
2005-10-07 06:11:12 +00:00
else {
2006-01-19 09:22:16 +00:00
$key = ( string ) $key ;
2007-04-23 17:00:36 +00:00
if ( $value_valid && ( ! $value_is_array && ( string ) $element [ '#value' ] === $key || ( $value_is_array && in_array ( $key , $element [ '#value' ])))) {
2006-01-06 07:15:47 +00:00
$selected = ' selected="selected"' ;
}
else {
$selected = '' ;
}
2007-12-05 18:13:03 +00:00
$options .= '<option value="' . check_plain ( $key ) . '"' . $selected . '>' . check_plain ( $choice ) . '</option>' ;
2005-10-07 06:11:12 +00:00
}
}
2006-01-19 09:22:16 +00:00
return $options ;
2005-10-07 06:11:12 +00:00
}
2006-12-29 00:19:58 +00:00
/**
2007-01-05 19:08:30 +00:00
* Traverses a select element ' s #option array looking for any values
* that hold the given key . Returns an array of indexes that match .
*
* This function is useful if you need to modify the options that are
2007-01-23 19:17:55 +00:00
* already in a form element ; for example , to remove choices which are
2007-01-05 19:08:30 +00:00
* not valid because of additional filters imposed by another module .
* One example might be altering the choices in a taxonomy selector .
* To correctly handle the case of a multiple hierarchy taxonomy ,
* #options arrays can now hold an array of objects, instead of a
* direct mapping of keys to labels , so that multiple choices in the
* selector can have the same key ( and label ) . This makes it difficult
* to manipulate directly , which is why this helper function exists .
*
* This function does not support optgroups ( when the elements of the
* #options array are themselves arrays), and will return FALSE if
* arrays are found . The caller must either flatten / restore or
* manually do their manipulations in this case , since returning the
* index is not sufficient , and supporting this would make the
* " helper " too complicated and cumbersome to be of any help .
*
* As usual with functions that can return array () or FALSE , do not
* forget to use === and !== if needed .
2006-12-29 00:19:58 +00:00
*
* @ param $element
2007-01-05 19:08:30 +00:00
* The select element to search .
2006-12-29 00:19:58 +00:00
* @ param $key
* The key to look for .
* @ return
2007-01-05 19:08:30 +00:00
* An array of indexes that match the given $key . Array will be
* empty if no elements were found . FALSE if optgroups were found .
2006-12-29 00:19:58 +00:00
*/
2007-01-05 19:08:30 +00:00
function form_get_options ( $element , $key ) {
$keys = array ();
foreach ( $element [ '#options' ] as $index => $choice ) {
if ( is_array ( $choice )) {
return FALSE ;
}
else if ( is_object ( $choice )) {
if ( isset ( $choice -> option [ $key ])) {
$keys [] = $index ;
}
}
else if ( $index == $key ) {
$keys [] = $index ;
2006-12-29 00:19:58 +00:00
}
}
2007-01-05 19:08:30 +00:00
return $keys ;
2006-12-29 00:19:58 +00:00
}
2005-10-07 06:11:12 +00:00
/**
* Format a group of form items .
*
* @ param $element
* An associative array containing the properties of the element .
2006-01-24 08:20:45 +00:00
* Properties used : attributes , title , value , description , children , collapsible , collapsed
2005-10-07 06:11:12 +00:00
* @ return
* A themed HTML string representing the form item group .
2007-12-06 09:58:34 +00:00
*
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
function theme_fieldset ( $element ) {
2005-10-11 19:44:35 +00:00
if ( $element [ '#collapsible' ]) {
2005-10-07 06:11:12 +00:00
drupal_add_js ( 'misc/collapse.js' );
2006-08-21 06:25:49 +00:00
if ( ! isset ( $element [ '#attributes' ][ 'class' ])) {
$element [ '#attributes' ][ 'class' ] = '' ;
}
2005-10-11 19:44:35 +00:00
$element [ '#attributes' ][ 'class' ] .= ' collapsible' ;
if ( $element [ '#collapsed' ]) {
2007-12-08 14:06:23 +00:00
$element [ '#attributes' ][ 'class' ] .= ' collapsed' ;
2005-10-07 06:11:12 +00:00
}
}
2007-04-13 08:56:59 +00:00
return '<fieldset' . drupal_attributes ( $element [ '#attributes' ]) . '>' . ( $element [ '#title' ] ? '<legend>' . $element [ '#title' ] . '</legend>' : '' ) . ( isset ( $element [ '#description' ]) && $element [ '#description' ] ? '<div class="description">' . $element [ '#description' ] . '</div>' : '' ) . ( ! empty ( $element [ '#children' ]) ? $element [ '#children' ] : '' ) . $element [ '#value' ] . " </fieldset> \n " ;
2005-10-07 06:11:12 +00:00
}
/**
* Format a radio button .
*
* @ param $element
* An associative array containing the properties of the element .
2006-01-18 19:04:12 +00:00
* Properties used : required , return_value , value , attributes , title , description
2005-10-07 06:11:12 +00:00
* @ return
* A themed HTML string representing the form item group .
2007-12-06 09:58:34 +00:00
*
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
function theme_radio ( $element ) {
2006-04-05 18:12:48 +00:00
_form_set_class ( $element , array ( 'form-radio' ));
2005-10-07 06:11:12 +00:00
$output = '<input type="radio" ' ;
2007-04-13 08:56:59 +00:00
$output .= 'name="' . $element [ '#name' ] . '" ' ;
2005-10-11 19:44:35 +00:00
$output .= 'value="' . $element [ '#return_value' ] . '" ' ;
2007-12-05 18:13:03 +00:00
$output .= ( check_plain ( $element [ '#value' ]) == $element [ '#return_value' ]) ? ' checked="checked" ' : ' ' ;
2005-10-11 19:44:35 +00:00
$output .= drupal_attributes ( $element [ '#attributes' ]) . ' />' ;
if ( ! is_null ( $element [ '#title' ])) {
$output = '<label class="option">' . $output . ' ' . $element [ '#title' ] . '</label>' ;
2005-10-07 06:11:12 +00:00
}
2006-05-02 09:26:33 +00:00
unset ( $element [ '#title' ]);
return theme ( 'form_element' , $element , $output );
2005-10-07 06:11:12 +00:00
}
/**
* Format a set of radio buttons .
*
* @ param $element
* An associative array containing the properties of the element .
2006-01-18 19:04:12 +00:00
* Properties used : title , value , options , description , required and attributes .
2005-10-07 06:11:12 +00:00
* @ return
* A themed HTML string representing the radio button set .
2007-12-06 09:58:34 +00:00
*
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
function theme_radios ( $element ) {
2006-12-12 10:01:38 +00:00
$class = 'form-radios' ;
if ( isset ( $element [ '#attributes' ][ 'class' ])) {
$class .= ' ' . $element [ '#attributes' ][ 'class' ];
}
2007-01-31 15:49:26 +00:00
$element [ '#children' ] = '<div class="' . $class . '">' . ( ! empty ( $element [ '#children' ]) ? $element [ '#children' ] : '' ) . '</div>' ;
2005-10-11 19:44:35 +00:00
if ( $element [ '#title' ] || $element [ '#description' ]) {
2006-05-02 09:26:33 +00:00
unset ( $element [ '#id' ]);
return theme ( 'form_element' , $element , $element [ '#children' ]);
2005-10-07 06:11:12 +00:00
}
else {
2005-10-11 19:44:35 +00:00
return $element [ '#children' ];
2005-10-07 06:11:12 +00:00
}
}
2006-01-02 08:35:59 +00:00
/**
* Format a password_confirm item .
*
* @ param $element
* An associative array containing the properties of the element .
* Properties used : title , value , id , required , error .
* @ return
* A themed HTML string representing the form item .
2007-12-06 09:58:34 +00:00
*
* @ ingroup themeable
2006-01-02 08:35:59 +00:00
*/
function theme_password_confirm ( $element ) {
2006-08-03 14:08:30 +00:00
return theme ( 'form_element' , $element , $element [ '#children' ]);
2006-01-02 08:35:59 +00:00
}
2006-04-20 16:35:29 +00:00
/*
* Expand a password_confirm field into two text boxes .
*/
function expand_password_confirm ( $element ) {
2006-08-03 14:08:30 +00:00
$element [ 'pass1' ] = array (
'#type' => 'password' ,
'#title' => t ( 'Password' ),
2007-05-14 13:43:38 +00:00
'#value' => empty ( $element [ '#value' ]) ? NULL : $element [ '#value' ][ 'pass1' ],
2007-05-31 12:36:18 +00:00
'#required' => $element [ '#required' ],
2007-06-08 06:04:15 +00:00
'#attributes' => array ( 'class' => 'password-field' ),
2006-08-03 14:08:30 +00:00
);
$element [ 'pass2' ] = array (
'#type' => 'password' ,
'#title' => t ( 'Confirm password' ),
2007-05-14 13:43:38 +00:00
'#value' => empty ( $element [ '#value' ]) ? NULL : $element [ '#value' ][ 'pass2' ],
2007-05-31 12:36:18 +00:00
'#required' => $element [ '#required' ],
2007-06-08 06:04:15 +00:00
'#attributes' => array ( 'class' => 'password-confirm' ),
2006-08-03 14:08:30 +00:00
);
2007-05-14 13:43:38 +00:00
$element [ '#element_validate' ] = array ( 'password_confirm_validate' );
2006-04-20 16:35:29 +00:00
$element [ '#tree' ] = TRUE ;
2007-01-11 03:24:42 +00:00
if ( isset ( $element [ '#size' ])) {
$element [ 'pass1' ][ '#size' ] = $element [ 'pass2' ][ '#size' ] = $element [ '#size' ];
}
2006-04-20 16:35:29 +00:00
return $element ;
}
2006-01-02 08:35:59 +00:00
/**
2006-01-24 10:15:03 +00:00
* Validate password_confirm element .
2006-01-02 08:35:59 +00:00
*/
2007-05-14 13:43:38 +00:00
function password_confirm_validate ( $form , & $form_state ) {
2006-04-25 20:44:00 +00:00
$pass1 = trim ( $form [ 'pass1' ][ '#value' ]);
if ( ! empty ( $pass1 )) {
2006-01-24 10:15:03 +00:00
$pass2 = trim ( $form [ 'pass2' ][ '#value' ]);
2006-01-02 08:35:59 +00:00
if ( $pass1 != $pass2 ) {
2006-01-24 10:15:03 +00:00
form_error ( $form , t ( 'The specified passwords do not match.' ));
2006-01-02 08:35:59 +00:00
}
2006-01-24 10:15:03 +00:00
}
2006-08-29 09:12:03 +00:00
elseif ( $form [ '#required' ] && ! empty ( $form [ '#post' ])) {
2006-04-20 16:35:29 +00:00
form_error ( $form , t ( 'Password field is required.' ));
2006-01-02 08:35:59 +00:00
}
2006-04-20 16:35:29 +00:00
2006-04-25 20:44:00 +00:00
// Password field must be converted from a two-element array into a single
// string regardless of validation results.
2007-05-14 13:43:38 +00:00
form_set_value ( $form [ 'pass1' ], NULL , $form_state );
form_set_value ( $form [ 'pass2' ], NULL , $form_state );
form_set_value ( $form , $pass1 , $form_state );
2006-04-25 20:44:00 +00:00
2006-01-02 08:35:59 +00:00
return $form ;
2007-05-28 06:08:47 +00:00
2006-01-02 08:35:59 +00:00
}
2005-10-07 06:11:12 +00:00
/**
2005-11-21 09:42:14 +00:00
* Format a date selection element .
2005-10-07 06:11:12 +00:00
*
* @ param $element
* An associative array containing the properties of the element .
2006-01-18 19:04:12 +00:00
* Properties used : title , value , options , description , required and attributes .
2005-10-07 06:11:12 +00:00
* @ return
2005-11-21 09:42:14 +00:00
* A themed HTML string representing the date selection boxes .
2007-12-06 09:58:34 +00:00
*
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
function theme_date ( $element ) {
2006-05-02 09:26:33 +00:00
return theme ( 'form_element' , $element , '<div class="container-inline">' . $element [ '#children' ] . '</div>' );
2005-10-07 06:11:12 +00:00
}
/**
2005-11-21 09:42:14 +00:00
* Roll out a single date element .
2005-10-07 06:11:12 +00:00
*/
function expand_date ( $element ) {
// Default to current date
2007-05-07 07:29:23 +00:00
if ( empty ( $element [ '#value' ])) {
2005-10-11 19:44:35 +00:00
$element [ '#value' ] = array ( 'day' => format_date ( time (), 'custom' , 'j' ),
2005-10-07 06:11:12 +00:00
'month' => format_date ( time (), 'custom' , 'n' ),
'year' => format_date ( time (), 'custom' , 'Y' ));
}
2006-01-02 08:04:02 +00:00
$element [ '#tree' ] = TRUE ;
2005-10-07 06:11:12 +00:00
// Determine the order of day, month, year in the site's chosen date format.
2006-09-06 06:53:39 +00:00
$format = variable_get ( 'date_format_short' , 'm/d/Y - H:i' );
2005-10-07 06:11:12 +00:00
$sort = array ();
$sort [ 'day' ] = max ( strpos ( $format , 'd' ), strpos ( $format , 'j' ));
$sort [ 'month' ] = max ( strpos ( $format , 'm' ), strpos ( $format , 'M' ));
$sort [ 'year' ] = strpos ( $format , 'Y' );
asort ( $sort );
$order = array_keys ( $sort );
2007-01-23 19:17:55 +00:00
// Output multi-selector for date.
2005-10-07 06:11:12 +00:00
foreach ( $order as $type ) {
switch ( $type ) {
case 'day' :
$options = drupal_map_assoc ( range ( 1 , 31 ));
break ;
case 'month' :
2005-11-21 09:42:14 +00:00
$options = drupal_map_assoc ( range ( 1 , 12 ), 'map_month' );
2005-10-07 06:11:12 +00:00
break ;
case 'year' :
$options = drupal_map_assoc ( range ( 1900 , 2050 ));
break ;
}
2007-07-20 05:44:13 +00:00
$parents = $element [ '#parents' ];
$parents [] = $type ;
2005-12-14 13:22:19 +00:00
$element [ $type ] = array (
'#type' => 'select' ,
'#value' => $element [ '#value' ][ $type ],
'#attributes' => $element [ '#attributes' ],
'#options' => $options ,
);
2005-10-07 06:11:12 +00:00
}
return $element ;
}
2006-05-15 06:27:32 +00:00
/**
* Validates the date type to stop dates like February 30 , 2006.
*/
function date_validate ( $form ) {
if ( ! checkdate ( $form [ '#value' ][ 'month' ], $form [ '#value' ][ 'day' ], $form [ '#value' ][ 'year' ])) {
form_error ( $form , t ( 'The specified date is invalid.' ));
}
}
2005-11-21 09:42:14 +00:00
/**
* Helper function for usage with drupal_map_assoc to display month names .
*/
function map_month ( $month ) {
return format_date ( gmmktime ( 0 , 0 , 0 , $month , 2 , 1970 ), 'custom' , 'M' , 0 );
}
2005-10-07 06:11:12 +00:00
2006-01-26 13:39:48 +00:00
/**
* If no default value is set for weight select boxes , use 0.
*/
function weight_value ( & $form ) {
if ( isset ( $form [ '#default_value' ])) {
$form [ '#value' ] = $form [ '#default_value' ];
}
else {
$form [ '#value' ] = 0 ;
}
}
2005-10-07 06:11:12 +00:00
/**
2006-01-18 19:04:12 +00:00
* Roll out a single radios element to a list of radios ,
* using the options array as index .
2005-10-07 06:11:12 +00:00
*/
function expand_radios ( $element ) {
2005-10-11 19:44:35 +00:00
if ( count ( $element [ '#options' ]) > 0 ) {
foreach ( $element [ '#options' ] as $key => $choice ) {
2006-07-02 20:10:20 +00:00
if ( ! isset ( $element [ $key ])) {
2007-09-11 17:23:58 +00:00
// Generate the parents as the autogenerator does, so we will have a
// unique id for each radio button.
$parents_for_id = array_merge ( $element [ '#parents' ], array ( $key ));
2007-03-27 05:13:55 +00:00
$element [ $key ] = array (
'#type' => 'radio' ,
'#title' => $choice ,
2007-12-05 18:13:03 +00:00
'#return_value' => check_plain ( $key ),
2007-03-27 05:13:55 +00:00
'#default_value' => isset ( $element [ '#default_value' ]) ? $element [ '#default_value' ] : NULL ,
'#attributes' => $element [ '#attributes' ],
'#parents' => $element [ '#parents' ],
2007-09-11 17:23:58 +00:00
'#id' => form_clean_id ( 'edit-' . implode ( '-' , $parents_for_id )),
2007-03-27 05:13:55 +00:00
);
2005-10-07 06:11:12 +00:00
}
}
}
return $element ;
}
2007-07-04 15:42:38 +00:00
/**
* Add AHAH information about a form element to the page to communicate with
2007-10-05 09:35:09 +00:00
* javascript . If #ahah[path] is set on an element, this additional javascript is
2007-07-04 15:42:38 +00:00
* added to the page header to attach the AHAH behaviors . See ahah . js for more
* information .
*
* @ param $element
* An associative array containing the properties of the element .
* Properties used : ahah_event , ahah_path , ahah_wrapper , ahah_parameters ,
* ahah_effect .
* @ return
* None . Additional code is added to the header of the page using
* drupal_add_js .
*/
function form_expand_ahah ( $element ) {
static $js_added = array ();
2007-10-05 09:35:09 +00:00
// Add a reasonable default event handler if none specified.
if ( isset ( $element [ '#ahah' ][ 'path' ]) && ! isset ( $element [ '#ahah' ][ 'event' ])) {
switch ( $element [ '#type' ]) {
case 'submit' :
case 'button' :
case 'image_button' :
$element [ '#ahah' ][ 'event' ] = 'click' ;
break ;
case 'password' :
case 'textfield' :
case 'textarea' :
$element [ '#ahah' ][ 'event' ] = 'blur' ;
break ;
case 'radio' :
case 'checkbox' :
case 'select' :
$element [ '#ahah' ][ 'event' ] = 'change' ;
break ;
}
}
2007-07-04 15:42:38 +00:00
// Adding the same javascript settings twice will cause a recursion error,
// we avoid the problem by checking if the javascript has already been added.
2007-10-05 09:35:09 +00:00
if ( isset ( $element [ '#ahah' ][ 'path' ]) && isset ( $element [ '#ahah' ][ 'event' ]) && ! isset ( $js_added [ $element [ '#id' ]])) {
drupal_add_js ( 'misc/jquery.form.js' );
2007-07-04 15:42:38 +00:00
drupal_add_js ( 'misc/ahah.js' );
$ahah_binding = array (
2007-11-19 10:05:48 +00:00
'url' => url ( $element [ '#ahah' ][ 'path' ]),
'event' => $element [ '#ahah' ][ 'event' ],
'wrapper' => empty ( $element [ '#ahah' ][ 'wrapper' ]) ? NULL : $element [ '#ahah' ][ 'wrapper' ],
2007-10-05 09:35:09 +00:00
'selector' => empty ( $element [ '#ahah' ][ 'selector' ]) ? '#' . $element [ '#id' ] : $element [ '#ahah' ][ 'selector' ],
'effect' => empty ( $element [ '#ahah' ][ 'effect' ]) ? 'none' : $element [ '#ahah' ][ 'effect' ],
'method' => empty ( $element [ '#ahah' ][ 'method' ]) ? 'replace' : $element [ '#ahah' ][ 'method' ],
2007-10-10 10:24:25 +00:00
'progress' => empty ( $element [ '#ahah' ][ 'progress' ]) ? array ( 'type' => 'throbber' ) : $element [ '#ahah' ][ 'progress' ],
2007-11-19 10:05:48 +00:00
'button' => $element [ '#type' ] == 'submit' ? array ( $element [ '#name' ] => $element [ '#value' ]) : FALSE ,
2007-07-04 15:42:38 +00:00
);
2007-10-10 10:24:25 +00:00
// Convert a simple #ahah[progress] type string into an array.
if ( is_string ( $ahah_binding [ 'progress' ])) {
$ahah_binding [ 'progress' ] = array ( 'type' => $ahah_binding [ 'progress' ]);
}
// Change progress path to a full url.
if ( isset ( $ahah_binding [ 'progress' ][ 'path' ])) {
$ahah_binding [ 'progress' ][ 'url' ] = url ( $ahah_binding [ 'progress' ][ 'path' ]);
}
// Add progress.js if we're doing a bar display.
if ( $ahah_binding [ 'progress' ][ 'type' ] == 'bar' ) {
drupal_add_js ( 'misc/progress.js' );
}
2007-07-04 15:42:38 +00:00
drupal_add_js ( array ( 'ahah' => array ( $element [ '#id' ] => $ahah_binding )), 'setting' );
$js_added [ $element [ '#id' ]] = TRUE ;
2007-11-19 19:23:28 +00:00
$element [ '#cache' ] = TRUE ;
2007-07-04 15:42:38 +00:00
}
return $element ;
}
2005-10-07 06:11:12 +00:00
/**
* Format a form item .
*
* @ param $element
* An associative array containing the properties of the element .
2006-01-18 19:04:12 +00:00
* Properties used : title , value , description , required , error
2005-10-07 06:11:12 +00:00
* @ return
* A themed HTML string representing the form item .
2007-12-06 09:58:34 +00:00
*
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
function theme_item ( $element ) {
2007-01-31 15:49:26 +00:00
return theme ( 'form_element' , $element , $element [ '#value' ] . ( ! empty ( $element [ '#children' ]) ? $element [ '#children' ] : '' ));
2005-10-07 06:11:12 +00:00
}
/**
* Format a checkbox .
*
* @ param $element
* An associative array containing the properties of the element .
2006-01-18 19:04:12 +00:00
* Properties used : title , value , return_value , description , required
2005-10-07 06:11:12 +00:00
* @ return
* A themed HTML string representing the checkbox .
2007-12-06 09:58:34 +00:00
*
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
function theme_checkbox ( $element ) {
2006-04-05 18:12:48 +00:00
_form_set_class ( $element , array ( 'form-checkbox' ));
2005-10-07 06:11:12 +00:00
$checkbox = '<input ' ;
$checkbox .= 'type="checkbox" ' ;
2005-10-11 19:44:35 +00:00
$checkbox .= 'name="' . $element [ '#name' ] . '" ' ;
2007-04-13 08:56:59 +00:00
$checkbox .= 'id="' . $element [ '#id' ] . '" ' ;
2005-10-11 19:44:35 +00:00
$checkbox .= 'value="' . $element [ '#return_value' ] . '" ' ;
2006-04-13 19:50:13 +00:00
$checkbox .= $element [ '#value' ] ? ' checked="checked" ' : ' ' ;
2007-04-13 08:56:59 +00:00
$checkbox .= drupal_attributes ( $element [ '#attributes' ]) . ' />' ;
2005-10-11 19:44:35 +00:00
if ( ! is_null ( $element [ '#title' ])) {
$checkbox = '<label class="option">' . $checkbox . ' ' . $element [ '#title' ] . '</label>' ;
2005-10-07 06:11:12 +00:00
}
2006-05-02 09:26:33 +00:00
unset ( $element [ '#title' ]);
return theme ( 'form_element' , $element , $checkbox );
2005-10-07 06:11:12 +00:00
}
/**
* Format a set of checkboxes .
*
* @ param $element
* An associative array containing the properties of the element .
* @ return
* A themed HTML string representing the checkbox set .
2007-12-06 09:58:34 +00:00
*
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
function theme_checkboxes ( $element ) {
2006-12-12 10:01:38 +00:00
$class = 'form-checkboxes' ;
if ( isset ( $element [ '#attributes' ][ 'class' ])) {
$class .= ' ' . $element [ '#attributes' ][ 'class' ];
}
2007-01-31 15:49:26 +00:00
$element [ '#children' ] = '<div class="' . $class . '">' . ( ! empty ( $element [ '#children' ]) ? $element [ '#children' ] : '' ) . '</div>' ;
2005-10-11 19:44:35 +00:00
if ( $element [ '#title' ] || $element [ '#description' ]) {
2006-05-02 09:26:33 +00:00
unset ( $element [ '#id' ]);
return theme ( 'form_element' , $element , $element [ '#children' ]);
2005-10-07 06:11:12 +00:00
}
else {
2005-10-11 19:44:35 +00:00
return $element [ '#children' ];
2005-10-07 06:11:12 +00:00
}
}
function expand_checkboxes ( $element ) {
2005-10-11 19:44:35 +00:00
$value = is_array ( $element [ '#value' ]) ? $element [ '#value' ] : array ();
2005-10-26 01:24:09 +00:00
$element [ '#tree' ] = TRUE ;
2005-10-11 19:44:35 +00:00
if ( count ( $element [ '#options' ]) > 0 ) {
if ( ! isset ( $element [ '#default_value' ]) || $element [ '#default_value' ] == 0 ) {
$element [ '#default_value' ] = array ();
2005-10-07 06:11:12 +00:00
}
2005-10-11 19:44:35 +00:00
foreach ( $element [ '#options' ] as $key => $choice ) {
2005-10-07 06:11:12 +00:00
if ( ! isset ( $element [ $key ])) {
2006-01-08 16:04:58 +00:00
$element [ $key ] = array ( '#type' => 'checkbox' , '#processed' => TRUE , '#title' => $choice , '#return_value' => $key , '#default_value' => isset ( $value [ $key ]), '#attributes' => $element [ '#attributes' ]);
2005-10-07 06:11:12 +00:00
}
}
}
return $element ;
}
2007-12-06 09:58:34 +00:00
/**
* Theme a form submit button .
*
* @ ingroup themeable
*/
2005-10-07 06:11:12 +00:00
function theme_submit ( $element ) {
return theme ( 'button' , $element );
}
2007-12-06 09:58:34 +00:00
/**
* Theme a form button .
*
* @ ingroup themeable
*/
2005-10-07 06:11:12 +00:00
function theme_button ( $element ) {
2007-01-15 04:09:40 +00:00
// Make sure not to overwrite classes.
2006-03-16 15:32:44 +00:00
if ( isset ( $element [ '#attributes' ][ 'class' ])) {
$element [ '#attributes' ][ 'class' ] = 'form-' . $element [ '#button_type' ] . ' ' . $element [ '#attributes' ][ 'class' ];
}
else {
$element [ '#attributes' ][ 'class' ] = 'form-' . $element [ '#button_type' ];
}
2006-03-29 23:29:41 +00:00
2007-04-13 08:56:59 +00:00
return '<input type="submit" ' . ( empty ( $element [ '#name' ]) ? '' : 'name="' . $element [ '#name' ] . '" ' ) . 'id="' . $element [ '#id' ] . '" value="' . check_plain ( $element [ '#value' ]) . '" ' . drupal_attributes ( $element [ '#attributes' ]) . " /> \n " ;
2005-10-07 06:11:12 +00:00
}
2007-07-29 17:28:23 +00:00
/**
2007-12-06 09:58:34 +00:00
* Theme a form image button .
*
* @ ingroup themeable
2007-07-29 17:28:23 +00:00
*/
function theme_image_button ( $element ) {
// Make sure not to overwrite classes.
if ( isset ( $element [ '#attributes' ][ 'class' ])) {
$element [ '#attributes' ][ 'class' ] = 'form-' . $element [ '#button_type' ] . ' ' . $element [ '#attributes' ][ 'class' ];
}
else {
$element [ '#attributes' ][ 'class' ] = 'form-' . $element [ '#button_type' ];
}
2007-09-04 21:10:45 +00:00
return '<input type="image" name="' . $element [ '#name' ] . '" ' .
2007-07-29 17:28:23 +00:00
( ! empty ( $element [ '#value' ]) ? ( 'value="' . check_plain ( $element [ '#value' ]) . '" ' ) : '' ) .
2007-09-04 21:10:45 +00:00
'id="' . $element [ '#id' ] . '" ' .
2007-07-29 17:28:23 +00:00
drupal_attributes ( $element [ '#attributes' ]) .
2007-09-04 21:10:45 +00:00
' src="' . base_path () . $element [ '#src' ] . '" ' .
( ! empty ( $element [ '#title' ]) ? 'alt="' . check_plain ( $element [ '#title' ]) . '" title="' . check_plain ( $element [ '#title' ]) . '" ' : '' ) .
2007-07-29 17:28:23 +00:00
" /> \n " ;
}
2005-10-07 06:11:12 +00:00
/**
* Format a hidden form field .
*
* @ param $element
* An associative array containing the properties of the element .
2006-01-18 19:04:12 +00:00
* Properties used : value , edit
2005-10-07 06:11:12 +00:00
* @ return
* A themed HTML string representing the hidden form field .
2007-12-06 09:58:34 +00:00
*
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
function theme_hidden ( $element ) {
2007-04-13 08:56:59 +00:00
return '<input type="hidden" name="' . $element [ '#name' ] . '" id="' . $element [ '#id' ] . '" value="' . check_plain ( $element [ '#value' ]) . " \" " . drupal_attributes ( $element [ '#attributes' ]) . " /> \n " ;
2005-10-07 06:11:12 +00:00
}
2007-12-06 09:58:34 +00:00
/**
* Format a form token .
*
* @ ingroup themeable
*/
2006-10-31 08:06:18 +00:00
function theme_token ( $element ) {
return theme ( 'hidden' , $element );
}
2005-10-07 06:11:12 +00:00
/**
* Format a textfield .
*
* @ param $element
* An associative array containing the properties of the element .
2006-01-18 19:04:12 +00:00
* Properties used : title , value , description , size , maxlength , required , attributes autocomplete_path
2005-10-07 06:11:12 +00:00
* @ return
* A themed HTML string representing the textfield .
2007-12-06 09:58:34 +00:00
*
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
function theme_textfield ( $element ) {
2007-08-09 10:43:03 +00:00
$size = empty ( $element [ '#size' ]) ? '' : ' size="' . $element [ '#size' ] . '"' ;
$maxlength = empty ( $element [ '#maxlength' ]) ? '' : ' maxlength="' . $element [ '#maxlength' ] . '"' ;
2006-04-05 18:12:48 +00:00
$class = array ( 'form-text' );
2006-01-24 08:20:45 +00:00
$extra = '' ;
2006-08-26 09:56:17 +00:00
$output = '' ;
2005-10-11 19:44:35 +00:00
if ( $element [ '#autocomplete_path' ]) {
2005-10-07 06:11:12 +00:00
drupal_add_js ( 'misc/autocomplete.js' );
2006-04-05 18:12:48 +00:00
$class [] = 'form-autocomplete' ;
2007-02-15 11:40:19 +00:00
$extra = '<input class="autocomplete" type="hidden" id="' . $element [ '#id' ] . '-autocomplete" value="' . check_url ( url ( $element [ '#autocomplete_path' ], array ( 'absolute' => TRUE ))) . '" disabled="disabled" />' ;
2005-10-07 06:11:12 +00:00
}
2006-04-05 18:12:48 +00:00
_form_set_class ( $element , $class );
2006-08-26 09:56:17 +00:00
if ( isset ( $element [ '#field_prefix' ])) {
$output .= '<span class="field-prefix">' . $element [ '#field_prefix' ] . '</span> ' ;
}
2007-08-09 10:43:03 +00:00
$output .= '<input type="text"' . $maxlength . ' name="' . $element [ '#name' ] . '" id="' . $element [ '#id' ] . '"' . $size . ' value="' . check_plain ( $element [ '#value' ]) . '"' . drupal_attributes ( $element [ '#attributes' ]) . ' />' ;
2006-08-26 09:56:17 +00:00
if ( isset ( $element [ '#field_suffix' ])) {
$output .= ' <span class="field-suffix">' . $element [ '#field_suffix' ] . '</span>' ;
}
2007-04-13 08:56:59 +00:00
return theme ( 'form_element' , $element , $output ) . $extra ;
2005-10-07 06:11:12 +00:00
}
/**
* Format a form .
*
* @ param $element
* An associative array containing the properties of the element .
2006-01-18 19:04:12 +00:00
* Properties used : action , method , attributes , children
2005-10-07 06:11:12 +00:00
* @ return
* A themed HTML string representing the form .
2007-12-06 09:58:34 +00:00
*
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
function theme_form ( $element ) {
2006-04-11 11:33:15 +00:00
// Anonymous div to satisfy XHTML compliance.
2007-04-13 08:56:59 +00:00
$action = $element [ '#action' ] ? 'action="' . check_url ( $element [ '#action' ]) . '" ' : '' ;
2007-11-23 12:02:38 +00:00
return '<form ' . $action . ' accept-charset="UTF-8" method="' . $element [ '#method' ] . '" id="' . $element [ '#id' ] . '"' . drupal_attributes ( $element [ '#attributes' ]) . " > \n <div> " . $element [ '#children' ] . " \n </div></form> \n " ;
2005-10-07 06:11:12 +00:00
}
/**
* Format a textarea .
*
* @ param $element
* An associative array containing the properties of the element .
2006-01-18 19:04:12 +00:00
* Properties used : title , value , description , rows , cols , required , attributes
2005-10-07 06:11:12 +00:00
* @ return
* A themed HTML string representing the textarea .
2007-12-06 09:58:34 +00:00
*
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
function theme_textarea ( $element ) {
2006-04-07 13:22:12 +00:00
$class = array ( 'form-textarea' );
2007-04-09 13:58:03 +00:00
2007-10-21 18:59:02 +00:00
// Add teaser behavior (must come before resizable)
2007-04-09 13:58:03 +00:00
if ( ! empty ( $element [ '#teaser' ])) {
drupal_add_js ( 'misc/teaser.js' );
// Note: arrays are merged in drupal_get_js().
drupal_add_js ( array ( 'teaserCheckbox' => array ( $element [ '#id' ] => $element [ '#teaser_checkbox' ])), 'setting' );
drupal_add_js ( array ( 'teaser' => array ( $element [ '#id' ] => $element [ '#teaser' ])), 'setting' );
$class [] = 'teaser' ;
}
2007-10-21 18:59:02 +00:00
// Add resizable behavior
2006-07-05 11:45:51 +00:00
if ( $element [ '#resizable' ] !== FALSE ) {
2005-12-29 03:59:30 +00:00
drupal_add_js ( 'misc/textarea.js' );
2006-04-05 18:12:48 +00:00
$class [] = 'resizable' ;
2005-12-29 03:59:30 +00:00
}
2006-04-05 18:12:48 +00:00
_form_set_class ( $element , $class );
2007-10-15 21:19:00 +00:00
return theme ( 'form_element' , $element , '<textarea cols="' . $element [ '#cols' ] . '" rows="' . $element [ '#rows' ] . '" name="' . $element [ '#name' ] . '" id="' . $element [ '#id' ] . '" ' . drupal_attributes ( $element [ '#attributes' ]) . '>' . check_plain ( $element [ '#value' ]) . '</textarea>' );
2005-10-07 06:11:12 +00:00
}
/**
* Format HTML markup for use in forms .
*
* This is used in more advanced forms , such as theme selection and filter format .
*
* @ param $element
* An associative array containing the properties of the element .
2006-05-02 09:26:33 +00:00
* Properties used : value , children .
2005-10-07 06:11:12 +00:00
* @ return
* A themed HTML string representing the HTML markup .
2007-12-06 09:58:34 +00:00
*
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
function theme_markup ( $element ) {
2006-11-16 09:06:59 +00:00
return ( isset ( $element [ '#value' ]) ? $element [ '#value' ] : '' ) . ( isset ( $element [ '#children' ]) ? $element [ '#children' ] : '' );
2005-10-07 06:11:12 +00:00
}
/**
2007-05-04 09:41:37 +00:00
* Format a password field .
*
* @ param $element
* An associative array containing the properties of the element .
* Properties used : title , value , description , size , maxlength , required , attributes
* @ return
* A themed HTML string representing the form .
2007-12-06 09:58:34 +00:00
*
* @ ingroup themeable
2007-05-04 09:41:37 +00:00
*/
2005-10-07 06:11:12 +00:00
function theme_password ( $element ) {
2005-10-11 19:44:35 +00:00
$size = $element [ '#size' ] ? ' size="' . $element [ '#size' ] . '" ' : '' ;
2006-10-18 11:43:27 +00:00
$maxlength = $element [ '#maxlength' ] ? ' maxlength="' . $element [ '#maxlength' ] . '" ' : '' ;
2005-10-07 06:11:12 +00:00
2006-04-05 18:12:48 +00:00
_form_set_class ( $element , array ( 'form-text' ));
2006-10-18 11:43:27 +00:00
$output = '<input type="password" name="' . $element [ '#name' ] . '" id="' . $element [ '#id' ] . '" ' . $maxlength . $size . drupal_attributes ( $element [ '#attributes' ]) . ' />' ;
2006-05-02 09:26:33 +00:00
return theme ( 'form_element' , $element , $output );
2005-10-07 06:11:12 +00:00
}
/**
2006-05-04 09:57:14 +00:00
* Expand weight elements into selects .
2005-10-07 06:11:12 +00:00
*/
2006-05-04 09:57:14 +00:00
function process_weight ( $element ) {
2005-10-11 19:44:35 +00:00
for ( $n = ( - 1 * $element [ '#delta' ]); $n <= $element [ '#delta' ]; $n ++ ) {
2005-10-07 06:11:12 +00:00
$weights [ $n ] = $n ;
}
2005-10-11 19:44:35 +00:00
$element [ '#options' ] = $weights ;
$element [ '#type' ] = 'select' ;
2006-05-04 09:57:14 +00:00
$element [ '#is_weight' ] = TRUE ;
2007-01-31 15:49:26 +00:00
$element += _element_info ( 'select' );
2006-05-04 09:57:14 +00:00
return $element ;
2005-10-07 06:11:12 +00:00
}
/**
* Format a file upload field .
*
* @ param $title
* The label for the file upload field .
* @ param $name
* The internal name used to refer to the field .
* @ param $size
* A measure of the visible size of the field ( passed directly to HTML ) .
* @ param $description
* Explanatory text to display after the form item .
* @ param $required
* Whether the user must upload a file to the field .
* @ return
* A themed HTML string representing the field .
*
2007-12-06 09:58:34 +00:00
* @ ingroup themeable
*
2005-10-07 06:11:12 +00:00
* For assistance with handling the uploaded file correctly , see the API
* provided by file . inc .
*/
function theme_file ( $element ) {
2006-04-05 18:12:48 +00:00
_form_set_class ( $element , array ( 'form-file' ));
2006-12-12 09:39:50 +00:00
return theme ( 'form_element' , $element , '<input type="file" name="' . $element [ '#name' ] . '"' . ( $element [ '#attributes' ] ? ' ' . drupal_attributes ( $element [ '#attributes' ]) : '' ) . ' id="' . $element [ '#id' ] . '" size="' . $element [ '#size' ] . " \" /> \n " );
2006-05-02 09:26:33 +00:00
}
/**
* Return a themed form element .
*
* @ param element
* An associative array containing the properties of the element .
* Properties used : title , description , id , required
* @ param $value
2007-01-23 19:17:55 +00:00
* The form element ' s data .
2006-05-02 09:26:33 +00:00
* @ return
2007-01-23 19:17:55 +00:00
* A string representing the form element .
2007-12-06 09:58:34 +00:00
*
* @ ingroup themeable
2006-05-02 09:26:33 +00:00
*/
function theme_form_element ( $element , $value ) {
2007-11-11 16:14:45 +00:00
// This is also used in the installer, pre-database setup.
$t = get_t ();
2007-11-13 14:04:08 +00:00
2007-03-25 19:57:56 +00:00
$output = '<div class="form-item"' ;
if ( ! empty ( $element [ '#id' ])) {
$output .= ' id="' . $element [ '#id' ] . '-wrapper"' ;
}
$output .= " > \n " ;
2007-11-11 16:14:45 +00:00
$required = ! empty ( $element [ '#required' ]) ? '<span class="form-required" title="' . $t ( 'This field is required.' ) . '">*</span>' : '' ;
2006-05-02 09:26:33 +00:00
if ( ! empty ( $element [ '#title' ])) {
$title = $element [ '#title' ];
if ( ! empty ( $element [ '#id' ])) {
2007-12-05 18:13:03 +00:00
$output .= ' <label for="' . $element [ '#id' ] . '">' . $t ( '!title: !required' , array ( '!title' => filter_xss_admin ( $title ), '!required' => $required )) . " </label> \n " ;
2006-05-02 09:26:33 +00:00
}
else {
2007-12-05 18:13:03 +00:00
$output .= ' <label>' . $t ( '!title: !required' , array ( '!title' => filter_xss_admin ( $title ), '!required' => $required )) . " </label> \n " ;
2006-05-02 09:26:33 +00:00
}
}
$output .= " $value\n " ;
if ( ! empty ( $element [ '#description' ])) {
$output .= ' <div class="description">' . $element [ '#description' ] . " </div> \n " ;
}
$output .= " </div> \n " ;
return $output ;
2005-10-07 06:11:12 +00:00
}
2006-01-24 10:15:03 +00:00
2006-04-05 18:12:48 +00:00
/**
* Sets a form element ' s class attribute .
*
* Adds 'required' and 'error' classes as needed .
*
* @ param & $element
2007-01-23 19:17:55 +00:00
* The form element .
2006-04-05 18:12:48 +00:00
* @ param $name
2007-01-23 19:17:55 +00:00
* Array of new class names to be added .
2006-04-05 18:12:48 +00:00
*/
function _form_set_class ( & $element , $class = array ()) {
if ( $element [ '#required' ]) {
$class [] = 'required' ;
}
2007-04-13 08:56:59 +00:00
if ( form_get_error ( $element )) {
2006-04-05 18:12:48 +00:00
$class [] = 'error' ;
}
if ( isset ( $element [ '#attributes' ][ 'class' ])) {
$class [] = $element [ '#attributes' ][ 'class' ];
}
$element [ '#attributes' ][ 'class' ] = implode ( ' ' , $class );
2005-10-07 06:11:12 +00:00
}
/**
2007-10-25 15:32:56 +00:00
* Prepare an HTML ID attribute string for a form item .
2007-10-24 13:35:26 +00:00
*
* Remove invalid characters and guarantee uniqueness .
2005-10-07 06:11:12 +00:00
*
* @ param $id
2007-01-23 19:17:55 +00:00
* The ID to clean .
2007-10-24 13:35:26 +00:00
* @ param $flush
* If set to TRUE , the function will flush and reset the static array
* which is built to test the uniqueness of element IDs . This is only
* used if a form has completed the validation process . This parameter
* should never be set to TRUE if this function is being called to
* assign an ID to the #ID element.
2005-10-07 06:11:12 +00:00
* @ return
2007-01-23 19:17:55 +00:00
* The cleaned ID .
2005-10-07 06:11:12 +00:00
*/
2007-10-24 13:35:26 +00:00
function form_clean_id ( $id = NULL , $flush = FALSE ) {
static $seen_ids = array ();
if ( $flush ) {
$seen_ids = array ();
return ;
}
2006-12-12 09:39:50 +00:00
$id = str_replace ( array ( '][' , '_' , ' ' ), '-' , $id );
2007-10-24 13:35:26 +00:00
// Ensure IDs are unique. The first occurrence is held but left alone.
// Subsequent occurrences get a number appended to them. This incrementing
// will almost certainly break code that relies on explicit HTML IDs in
// forms that appear more than once on the page, but the alternative is
// outputting duplicate IDs, which would break JS code and XHTML
// validity anyways. For now, it's an acceptable stopgap solution.
if ( isset ( $seen_ids [ $id ])) {
$id = $id . '-' . $seen_ids [ $id ] ++ ;
}
else {
$seen_ids [ $id ] = 1 ;
}
2005-10-07 06:11:12 +00:00
return $id ;
}
/**
* @ } End of " defgroup form " .
*/
2007-05-04 09:41:37 +00:00
/**
* @ defgroup batch Batch operations
* @ {
* Functions allowing forms processing to be spread out over several page
* requests , thus ensuring that the processing does not get interrupted
* because of a PHP timeout , while allowing the user to receive feedback
* on the progress of the ongoing operations .
*
* The API is primarily designed to integrate nicely with the Form API
* workflow , but can also be used by non - FAPI scripts ( like update . php )
* or even simple page callbacks ( which should probably be used sparingly ) .
*
* Example :
* @ code
* $batch = array (
* 'title' => t ( 'Exporting' ),
* 'operations' => array (
* array ( 'my_function_1' , array ( $account -> uid , 'story' )),
* array ( 'my_function_2' , array ()),
* ),
* 'finished' => 'my_finished_callback' ,
* );
* batch_set ( $batch );
2007-05-14 13:43:38 +00:00
* // only needed if not inside a form _submit handler :
2007-05-04 09:41:37 +00:00
* batch_process ();
* @ endcode
*
* Sample batch operations :
* @ code
* // Simple and artificial: load a node of a given type for a given user
* function my_function_1 ( $uid , $type , & $context ) {
* // The $context array gathers batch context information about the execution (read),
* // as well as 'return values' for the current operation (write)
* // The following keys are provided :
* // 'results' (read / write): The array of results gathered so far by
2007-07-02 14:41:37 +00:00
* // the batch processing, for the current operation to append its own.
2007-05-04 09:41:37 +00:00
* // 'message' (write): A text message displayed in the progress page.
* // The following keys allow for multi-step operations :
* // 'sandbox' (read / write): An array that can be freely used to
* // store persistent data between iterations. It is recommended to
* // use this instead of $_SESSION, which is unsafe if the user
* // continues browsing in a separate window while the batch is processing.
* // 'finished' (write): A float number between 0 and 1 informing
* // the processing engine of the completion level for the operation.
2007-05-07 10:15:57 +00:00
* // 1 (or no value explicitly set) means the operation is finished
* // and the batch processing can continue to the next operation.
*
2007-05-04 09:41:37 +00:00
* $node = node_load ( array ( 'uid' => $uid , 'type' => $type ));
* $context [ 'results' ][] = $node -> nid . ' : ' . $node -> title ;
* $context [ 'message' ] = $node -> title ;
* }
*
2007-07-02 14:41:37 +00:00
* // More advanced example: multi-step operation - load all nodes, five by five
2007-05-04 09:41:37 +00:00
* function my_function_2 ( & $context ) {
* if ( empty ( $context [ 'sandbox' ])) {
* $context [ 'sandbox' ][ 'progress' ] = 0 ;
* $context [ 'sandbox' ][ 'current_node' ] = 0 ;
* $context [ 'sandbox' ][ 'max' ] = db_result ( db_query ( 'SELECT COUNT(DISTINCT nid) FROM {node}' ));
* }
* $limit = 5 ;
* $result = db_query_range ( " SELECT nid FROM { node} WHERE nid > %d ORDER BY nid ASC " , $context [ 'sandbox' ][ 'current_node' ], 0 , $limit );
* while ( $row = db_fetch_array ( $result )) {
* $node = node_load ( $row [ 'nid' ], NULL , TRUE );
* $context [ 'results' ][] = $node -> nid . ' : ' . $node -> title ;
* $context [ 'sandbox' ][ 'progress' ] ++ ;
* $context [ 'sandbox' ][ 'current_node' ] = $node -> nid ;
* $context [ 'message' ] = $node -> title ;
* }
* if ( $context [ 'sandbox' ][ 'progress' ] != $context [ 'sandbox' ][ 'max' ]) {
* $context [ 'finished' ] = $context [ 'sandbox' ][ 'progress' ] / $context [ 'sandbox' ][ 'max' ];
* }
* }
* @ endcode
*
* Sample 'finished' callback :
* @ code
* function batch_test_finished ( $success , $results , $operations ) {
* if ( $success ) {
2007-11-12 19:06:33 +00:00
* $message = format_plural ( count ( $results ), 'One post processed.' , '@count posts processed.' );
2007-05-04 09:41:37 +00:00
* }
* else {
* $message = t ( 'Finished with an error.' );
* }
* drupal_set_message ( $message );
2007-07-02 14:41:37 +00:00
* // Providing data for the redirected page is done through $_SESSION.
2007-05-04 09:41:37 +00:00
* foreach ( $results as $result ) {
* $items [] = t ( 'Loaded node %title.' , array ( '%title' => $result ));
* }
* $_SESSION [ 'my_batch_results' ] = $items ;
* }
* @ endcode
*/
/**
* Open a new batch .
*
* @ param $batch
* An array defining the batch . The following keys can be used :
* 'operations' : an array of function calls to be performed .
* Example :
* @ code
* array (
* array ( 'my_function_1' , array ( $arg1 )),
* array ( 'my_function_2' , array ( $arg2_1 , $arg2_2 )),
* )
* @ endcode
* All the other values below are optional .
* batch_init () provides default values for the messages .
* 'title' : title for the progress page .
* Defaults to t ( 'Processing' ) .
* 'init_message' : message displayed while the processing is initialized .
* Defaults to t ( 'Initializing.' ) .
* 'progress_message' : message displayed while processing the batch .
* Available placeholders are @ current , @ remaining , @ total and @ percent .
* Defaults to t ( 'Remaining @remaining of @total.' ) .
2007-10-15 15:18:39 +00:00
* 'error_message' : message displayed if an error occurred while processing
* the batch .
2007-05-04 09:41:37 +00:00
* Defaults to t ( 'An error has occurred.' ) .
2007-10-15 15:18:39 +00:00
* 'finished' : the name of a function to be executed after the batch has
* completed . This should be used to perform any result massaging that
* may be needed , and possibly save data in $_SESSION for display after
* final page redirection .
* 'file' : the path to the file containing the definitions of the
* 'operations' and 'finished' functions , for instance if they don ' t
* reside in the original '.module' file . The path should be relative to
* the base_path (), and thus should be built using drupal_get_path () .
2007-05-04 09:41:37 +00:00
*
* Operations are added as new batch sets . Batch sets are used to ensure
2007-07-02 14:41:37 +00:00
* clean code independence , ensuring that several batches submitted by
2007-05-04 09:41:37 +00:00
* different parts of the code ( core / contrib modules ) can be processed
* correctly while not interfering or having to cope with each other . Each
2007-11-26 16:36:44 +00:00
* batch set gets to specify his own UI messages , operates on its own set
* of operations and results , and triggers its own 'finished' callback .
2007-05-04 09:41:37 +00:00
* Batch sets are processed sequentially , with the progress bar starting
* fresh for every new set .
*/
function batch_set ( $batch_definition ) {
if ( $batch_definition ) {
$batch =& batch_get ();
// Initialize the batch
if ( empty ( $batch )) {
$batch = array (
'sets' => array (),
);
}
$init = array (
'sandbox' => array (),
'results' => array (),
'success' => FALSE ,
);
// Use get_t() to allow batches at install time.
$t = get_t ();
$defaults = array (
'title' => $t ( 'Processing' ),
'init_message' => $t ( 'Initializing.' ),
'progress_message' => $t ( 'Remaining @remaining of @total.' ),
'error_message' => $t ( 'An error has occurred.' ),
);
$batch_set = $init + $batch_definition + $defaults ;
// Tweak init_message to avoid the bottom of the page flickering down after init phase.
$batch_set [ 'init_message' ] .= '<br/> ' ;
$batch_set [ 'total' ] = count ( $batch_set [ 'operations' ]);
2007-05-14 13:43:38 +00:00
// If the batch is being processed (meaning we are executing a stored submit handler),
2007-05-04 09:41:37 +00:00
// insert the new set after the current one.
if ( isset ( $batch [ 'current_set' ])) {
// array_insert does not exist...
$slice1 = array_slice ( $batch [ 'sets' ], 0 , $batch [ 'current_set' ] + 1 );
$slice2 = array_slice ( $batch [ 'sets' ], $batch [ 'current_set' ] + 1 );
$batch [ 'sets' ] = array_merge ( $slice1 , array ( $batch_set ), $slice2 );
}
else {
$batch [ 'sets' ][] = $batch_set ;
}
}
}
/**
* Process the batch .
2007-05-06 05:47:52 +00:00
*
2007-07-02 14:41:37 +00:00
* Unless the batch has been marked with 'progressive' = FALSE , the function
2007-10-15 15:18:39 +00:00
* issues a drupal_goto and thus ends page execution .
2007-05-04 09:41:37 +00:00
*
2007-05-14 13:43:38 +00:00
* This function is not needed in form submit handlers ; Form API takes care
2007-07-20 05:44:13 +00:00
* of batches that were set during form submission .
2007-05-04 09:41:37 +00:00
*
* @ param $redirect
* ( optional ) Path to redirect to when the batch has finished processing .
* @ param $url
2007-07-02 14:41:37 +00:00
* ( optional - should only be used for separate scripts like update . php )
2007-05-04 09:41:37 +00:00
* URL of the batch processing page .
*/
function batch_process ( $redirect = NULL , $url = NULL ) {
$batch =& batch_get ();
if ( isset ( $batch )) {
// Add process information
$url = isset ( $url ) ? $url : 'batch' ;
$process_info = array (
'current_set' => 0 ,
'progressive' => TRUE ,
'url' => isset ( $url ) ? $url : 'batch' ,
'source_page' => $_GET [ 'q' ],
'redirect' => $redirect ,
);
$batch += $process_info ;
if ( $batch [ 'progressive' ]) {
2007-07-20 05:44:13 +00:00
// Clear the way for the drupal_goto redirection to the batch processing
// page, by saving and unsetting the 'destination' if any, on both places
// drupal_goto looks for it.
2007-05-04 09:41:37 +00:00
if ( isset ( $_REQUEST [ 'destination' ])) {
$batch [ 'destination' ] = $_REQUEST [ 'destination' ];
unset ( $_REQUEST [ 'destination' ]);
}
elseif ( isset ( $_REQUEST [ 'edit' ][ 'destination' ])) {
$batch [ 'destination' ] = $_REQUEST [ 'edit' ][ 'destination' ];
unset ( $_REQUEST [ 'edit' ][ 'destination' ]);
}
2007-07-20 05:44:13 +00:00
// Initiate db storage in order to get a batch id. We have to provide
// at least an empty string for the (not null) 'token' column.
db_query ( " INSERT INTO { batch} (token, timestamp) VALUES ('', %d) " , time ());
2007-06-05 12:13:23 +00:00
$batch [ 'id' ] = db_last_insert_id ( 'batch' , 'bid' );
2007-07-20 05:44:13 +00:00
// Now that we have a batch id, we can generate the redirection link in
// the generic error message.
$t = get_t ();
$batch [ 'error_message' ] = $t ( 'Please continue to <a href="@error_url">the error page</a>' , array ( '@error_url' => url ( $url , array ( 'query' => array ( 'id' => $batch [ 'id' ], 'op' => 'finished' )))));
// Actually store the batch data and the token generated form the batch id.
2007-06-05 12:13:23 +00:00
db_query ( " UPDATE { batch} SET token = '%s', batch = '%s' WHERE bid = %d " , drupal_get_token ( $batch [ 'id' ]), serialize ( $batch ), $batch [ 'id' ]);
2007-07-20 05:44:13 +00:00
2007-05-04 09:41:37 +00:00
drupal_goto ( $batch [ 'url' ], 'op=start&id=' . $batch [ 'id' ]);
}
else {
// Non-progressive execution: bypass the whole progressbar workflow
// and execute the batch in one pass.
require_once './includes/batch.inc' ;
_batch_process ();
}
}
}
/**
2007-07-02 14:41:37 +00:00
* Retrieve the current batch .
2007-05-04 09:41:37 +00:00
*/
function & batch_get () {
static $batch = array ();
return $batch ;
}
/**
* @ } End of " defgroup batch " .
*/