diff options
Diffstat (limited to 'includes/form.inc')
-rw-r--r-- | includes/form.inc | 1078 |
1 files changed, 1078 insertions, 0 deletions
diff --git a/includes/form.inc b/includes/form.inc new file mode 100644 index 000000000..0408db883 --- /dev/null +++ b/includes/form.inc @@ -0,0 +1,1078 @@ +<?php +/** + * @defgroup form Form generation + * @{ + * Functions to enable output of HTML forms and form elements. + * + * Drupal uses these functions to achieve consistency in its form presentation, + * while at the same time simplifying code and reducing the amount of HTML that + * must be explicitly generated by modules. + */ + +/** + * Form property constants. + * + * These constants are defined to keep the namespace of the form tree available for elements. + * Properties are strings that start with '_' (underscore) and have special meaning for the form api. + */ + +/** + * Keyword: type. + * Required: true + * Description: Used to specify the form element type. Form elements are defined by implementation of hook_elements. + */ +define('type', '_type'); + +define('theme', '_theme'); + +define('theme_used', '_theme_used'); +/** + * Keyword: name. + * Internal: For use within the form api. Should not be set by the developer. + * Description: The form_builder function populates this property based on the location of the form element in the form tree. + */ +define('name', '_name'); + +/** + * Keyword: id. + * Internal: For use within the form api. Should not be set by the developer. + * Description: The form_builder function populates this property based on the location of the form element in the form tree. + * This is used for the form_set_error notification, along with the stylesheets to be used. + */ +define('id', '_id'); + +/** + * Keyword: printed + * Internal: For use within the form api. Should not be set by the developer. + * Description: Used by form_render to ascertain wether or not a form element has been printed yet + */ +define('printed', '_printed'); + +/** + * Keyword: built + * Internal: For use within the form api. Should not be set by the developer. + * Description: Used by _form_builder to ascertain wether or not a form element has been built yet + */ +define('built', '_built'); + +/** + * Keyword: processed + * Internal: For use within the form api. Should not be set by the developer. + * Description: Used by _form_builder to ascertain wether or not a form element has been processed (ie: expanded to multiple elements) + */ +define('processed', '_processed'); + + +/** + * Keyword: variable + * Internal: For use within the form api. Should not be set by the developer. + * Description: used by form builder to populate a global form_variables array. + */ +define('variable', '_variable'); + +/** + * Keyword: id. + * Internal: For use within the form api. Should not be set by the developer. + * Description: The form_builder function uses this property to keep track of the parent form elements, and uses this to generate the id and name properties. + */ +define('parents', '_parents'); + +/** + * Keyword: input. + * Description: Wether or not an input is possible for this form element. True / False. Set in the hook_elements implementation. + */ +define('input', '_input'); + +/** + * Keyword: validated. + * Description: Wether or not an input has been validated. + */ +define('validated', '_validated'); + +/** + * Keyword: value. + * Used: For all form elements except 'textarea' and the 'default' fallback. + * Description: The value the form element should be set as. Setting this yourself is not required, although it might be a good idea for form elements that + * don't change. See the default_value property. + */ +define('value', '_value'); + +/** + * Keyword: default_value. + * Used: For all form elements that have a value property. + * Description: The value the form element should be initialized as. If no submission for this element exists, the element will be set to this value. + * This means that you do not have to set the value properties for form elements, as they will be automatically handled by the form api. + */ +define('default_value', '_default_value'); + +/** + * Keyword: return_value. + * Used: For select , radio and checkbox elements. + * Description: The value the form element will return. + */ +define('return_value', '_return_value'); + +/** + * Keyword: title + * Used: For all form elements that have visible output. + * Description: The title of the form element. The developer should use the t() function to translate this property. + */ +define('title', '_title'); + +/** + * Keyword: description + * Used: For all form elements that have visible output. + * Description: The description of the form element. The developer should use the t() function to translate this property. + */ +define('description', '_description'); + +/** + * Keyword: required + * Used: For all form elements that have visible output. + * Description: Wether or not the element is required. This automatically validates for empty fields, and flags inputs as required. + */ +define('required', '_required'); + +/** + * Keyword: cols + * Used: textarea elements. + * Description: How many columns wide the textarea should be. + */ +define('cols', '_cols'); + +/** + * Keyword: rows + * Used: textarea elements. + * Description: How many rows high the textarea should be. + */ +define('rows', '_rows'); + +/** + * Keyword: size + * Used: textfield elements. + * Description: How many characters wide should the textfield be. + */ +define('size', '_size'); + +/** + * Keyword: maxlength + * Used: For textfield element types. + * Description: The maximum amount of characters to accept as input. + */ +define('maxlength', '_maxlength'); + +/** + * Keyword: valid + * Used: For all form elements that have the value property. + * Description: A list of validation functions that need to be passed. + */ +define('valid', '_valid'); +define('validation_arguments', '_validation_arguments'); + +/** + * Keyword: weight + * Used: all elements. + * Description: Used by the form_render function to sort the list of elements before being output. + */ +define('weight', '_weight'); + +/** + * Keyword: collapsible + * Used: fieldset elements. + * Description: Wether or not the fieldset can be collapsed with javascript. + */ +define('collapsible', '_collapsible'); + +/** + * Keyword: collapsed + * Used: fieldset elements. + * Description: Wether or not the fieldset is collapsed by default. See collapsible property. + */ +define('collapsed', '_collapsed'); + +/** + * Keyword: autocomplete_path + * Used: textfield elements. + * Description: The path the AJAX autocomplete script uses as the source for autocompletion. + */ +define('autocomplete_path', '_autocomplete_path'); + +/** + * Keyword: action + * Used: form elements. + * Description: The path to which the form will be submitted. + */ +define('action', '_action'); + +/** + * Keyword: method + * Used: form elements. + * Description: The HTTP method the form will be submitted with (GET/POST). Default is 'post'. + */ +define('method', '_method'); + +/** + * Keyword: attributes + * Used: all visible form elements. + * Description: Additional html attributes, such as 'class' can be set using this mechanism. + */ +define('attributes', '_attributes'); + +/** + * Keyword: options + * Used: select boxes, checkboxes and radios form elements. + * Description: An associative array containing the options to be used. In the format 'return_value' => 'Display Value' + * + * 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. + */ +define('options', '_options'); + +/** + * Keyword: extra + * Used: select boxes. + * Description: Additional HTML to inject into the select element tag. + */ +define('extra', '_extra'); + +/** + * Keyword: multiple + * Used: select boxes. + * Description: Wether the user may select more than one item. + */ +define('multiple', '_multiple'); + +/** + * Keyword: button_type + * Used: buttons. + * Description: The type of button to display (cancel or submit) + */ +define('button_type', '_button_type'); + + + +/** + * Keyword: error + * Used: All visible form elements. + * Description: Wether or not a form element has been flagged as having an error. + */ +define('error', '_error'); + +/** + * Keyword: prefix + * Used: markup element. + * Description: Text to include before the value and children properties. + */ +define('prefix', '_prefix'); + +/** + * Keyword: suffix + * Used: markup element. + * Description: Text to include after the value and children properties. + */ +define('suffix', '_suffix'); + +/** + * Keyword: error + * Used: weight form element. + * Description: Number of weights to have selectable. + */ +define('delta', '_delta'); + +/** + * Multiple elements. For use in the poll module, and for file uploads. + */ + +/** + * Keyword : process + * Used : By any element, used to modify a form element. + */ +define('process', '_process'); + +/** + * Keyword: multiple + */ +define('multiple', '_multiple'); + +/** + * Keyword: min + */ +define('minimum', '_minimum'); + +/** + * Keyword: max + */ +define('maximum', '_maximum'); + +/** + * Keyword: increment + */ +define('increment', '_increment'); + +define('spawned', '_spawned'); + +define('tree', '_tree'); + +define('token', '_token'); + +define('execute', '_execute'); + +/** + * Check if the key is a property. + */ +function element_property($key) { + return (substr($key, 0, 1) == '_'); +} + +function element_properties($element) { + return array_filter(array_keys($element), 'element_property'); +} + +/** + * Check if the key is a child. + */ +function element_child($key) { + return (substr($key, 0, 1) != '_'); +} + +function element_children($element) { + return array_filter(array_keys($element), 'element_child'); +} + +/** + * Processes a form array, and produces the HTML output of a form. + * If there is input in the $_POST['edit'] variable, this function + * will attempt to validate it, using <code>drupal_validate_form</code>, + * and then execute the form using <code>drupal_execute_form</code>. + * + * @param $form_id + * A unique string identifying the form. Allows each form to be themed. + * @param $form + * An associative array containing the structure of the form. + * @param $callback + * An optional callback that will be used in addition to the form_id. + * + */ +function drupal_get_form($form_id, &$form, $callback = NULL) { + global $form_values, $form_execute; + $form_values = array(); + $form_execute = FALSE; + $form[type] = 'form'; + $form[attributes]['class'] .= ' form-api'; + if (isset($form[token])) { + $form['form_token'] = array(type => 'hidden', value => md5($_SERVER['REMOTE_ADDR'] . $form[token] . variable_get('drupal_private_key', ''))); + } + $form = array_merge(_element_info('form'), $form); + + foreach (module_implements('form_alter') as $module) { + $function = $module .'_form_alter'; + $function($form); + } + + $function = $form_id . '_alter'; + if (function_exists($function)) { + $function($form); + } + + if (!$form[built]) { + $form = _form_builder($form); + } + if ($form_execute) { + drupal_execute_form($form_id, $form, $callback); + } + + if (function_exists('theme_' . $form_id)) { + $form[theme] = $form_id; + } + elseif (function_exists('theme_' . $callback)) { + $form[theme] = $callback; + } + return form_render($form); +} + +function drupal_validate_form($form_id, &$form, $callback = NULL) { + global $form_values; + + if (isset($form[token])) { + if ($form_values['form_token'] != md5($_SERVER['REMOTE_ADDR'] . $form[token] . variable_get('drupal_private_key', ''))) { + // setting this error will cause the form to fail validation + form_set_error('form_token', t('Validation error, please try again. If this error persists, please contact the site administrator.')); + } + } + + foreach (module_implements('form_validate_alter') as $module) { + $function = $module .'_form_validate_alter'; + $function($form_id, $form_values); + } + + _form_validate($form); + + if (function_exists($form_id . '_validate')) { + call_user_func($form_id . '_validate', $form_id, $form_values); + } + if (function_exists($callback . '_validate')) { + call_user_func($callback . '_validate', $form_id, $form_values); + } +} + +function drupal_execute_form($form_id, $form, $callback = NULL) { + global $form_values; + if (!empty($_POST['edit'])) { + drupal_validate_form($form_id, $form, $callback); + if (!form_get_errors()) { + foreach (module_implements('form_execute_alter') as $module) { + $function = $module .'_form_execute_alter'; + $function($form_id, $form_values); + } + + if (function_exists($form_id . '_execute')) { + call_user_func($form_id . '_execute', $form_id, $form_values); + } + elseif (function_exists($callback . '_execute')) { + call_user_func($callback . '_execute', $form_id, $form_values); + } + } + } +} + +function _form_validate(&$elements) { + + // Recurse through all children. + foreach (element_children($elements) as $key) { + _form_validate($elements[$key]); + } + + /* Validate the current input */ + if (!$elements[validated] && $elements[input]) { + if ($elements[required]) { + if (!$elements[value]) { + form_error($elements, t('%name field is required', array('%name' => $elements[title]))); + } + if ($elements[valid]) { + if (is_array($elements[valid])) { + foreach ($elements[valid] as $key => $valid) { + $args = is_array($elements[validation_arguments][$key]) ? $elements[validation_arguments][$key] : array(); + if (function_exists('valid_' . $valid)) { + call_user_func_array('valid_' . $valid, array_merge(array($elements), $args)); + } + } + } + else { + $args = is_array($elements[validation_arguments]) ? $elements[validation_arguments] : array(); + if (function_exists('valid_' . $elements[valid])) { + call_user_func_array('valid_' . $elements[valid], array_merge(array($elements), $args)); + } + } + + } + } + $elements[validated] = TRUE; + } +} + +/** + * Flag an element as having an error. + */ +function form_error(&$element, $message) { + $element[error] = TRUE; + $GLOBALS['form'][$element[name]] = $message; + drupal_set_message($message, 'error'); +} + + +/** + * Adds some required properties to each form element, which are used internally in the form api. + * This function also automatically assigns the value property from the $edit array, provided the + * element doesn't already have an assigned value. + */ +function _form_builder($form, $parents = array(), $multiple = FALSE) { + global $form_values; + global $form_execute; + + if ($form[built] == TRUE) { + return $form; + } + $form[built] = TRUE; + + $form[parents] = ($form[parents]) ? $form[parents] : $parents; + /* Use element defaults */ + if ((!empty($form[type])) && ($info = _element_info($form[type]))) { + $form += $info; + } + + if ($form[input]) { + if (!$form[tree]) { + $form[parents] = array(array_pop($form[parents])); + } + + $form[name] = ($form[name]) ? $form[name] : 'edit[' . implode('][', $form[parents]) . ']'; + $form[id] = ($form[id]) ? $form[id] : 'edit-' . implode('-', $form[parents]); + + $posted = isset($_POST['edit']); + $edit = $posted ? $_POST['edit'] : array(); + $ref =& $form_values; + foreach ($form[parents] as $parent) { + $edit = isset($edit[$parent]) ? $edit[$parent] : NULL; + $ref =& $ref[$parent]; + } + $default_value = $posted ? $edit : $form[default_value]; + $form[value] = $form[value] ? $form[value] : $default_value; + if (isset($form[execute])) { + if ($_POST[$form[name]] == $form[value]) { + $form_execute = $form_execute || $form[execute]; + } + } + + $ref = $form[value]; + } + + // Allow for elements to expand to multiple elements. Radios, checkboxes and files for instance. + if (function_exists($form[process]) && !$form[processed]) { + $form = call_user_func($form[process], $form); + $form[processed] = TRUE; + } + + // Recurse through all child elements. + $count = 0; + foreach (element_children($form) as $key) { + $form[$key][tree] = (isset($form[$key][tree])) ? $form[$key][tree] : $form[tree]; + # Assign a decimal placeholder weight, to preserve original array order + $form[$key][weight] = $form[$key][weight] ? $form[$key][weight] : $count/10; + $form[$key] = _form_builder($form[$key], array_merge($form[parents], array($key))); + $count++; + } + + + return $form; +} + +/** + * Renders a HTML form given an form tree. Recursively iterates over each of + * each of the form elements generating HTML code. This function is usually + * called from within a theme. To render a form from within a module, use + * <code>drupal_get_form()</code>. + * + * @param $elements + * The form tree describing the form. + * @return + * The rendered HTML form. + */ +function form_render(&$elements) { + $content = ''; + if (is_array($elements)) { + uasort($elements, "_form_sort"); + } + + if (!$elements[children]) { + /* render all the children using a theme function */ + if ($elements[theme] && !$elements[theme_used]) { + $elements[theme_used] = TRUE; + $previous_type = $elements[type]; + $elements[type] = 'markup'; + $content = theme($elements[theme], $elements); + $elements[type] = $previous_type; + } + /* render each of the children using form_render and concatenate them */ + if (!$content) { + foreach (element_children($elements) as $key) { + $content .= form_render($elements[$key]); + } + } + } + if ($content) { + $elements[children] = $content; + } + + /* Call the form element renderer */ + if (!$elements[printed]) { + $content = theme(($elements[type]) ? $elements[type]: 'markup', $elements); + $elements[printed] = TRUE; + } + + return $elements[prefix] . $content . $elements[suffix]; +} + +function _print_rp($var) { + echo "<pre>"; + print_r($var); + echo "</pre>"; +} + +/** + * Function used by uasort in form render to sort form via weight. + */ +function _form_sort($a, $b) { + if ($a[weight] == $b[weight]) { + return 0; + } + return ($a[weight] < $b[weight]) ? -1 : 1; +} + +/** + * Retrieve the default properties for the defined element type. + */ +function _element_info($type, $refresh = null) { + static $cache; + $basic_defaults = array( + description => NULL, + attributes => array(), + required => FALSE, + tree => FALSE + ); + if ($refresh || !is_array($cache)) { + $cache = array(); + foreach (module_implements('elements') as $module) { + $elements = module_invoke($module, 'elements'); + if (is_array($elements)) { + $cache = array_merge($cache, $elements); + } + } + if (sizeof($cache)) { + foreach ($cache as $element_type => $info) { + $cache[$element_type] = array_merge($basic_defaults, $info); + } + } + } + + return $cache[$type]; +} + +/** + * Format a dropdown menu or scrolling selection box. + * + * @param $element + * An associative array containing the properties of the element. + * Properties used : title, value, options, description, extra, multiple, required + * @return + * A themed HTML string representing the form element. + * + * 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 = ''; + foreach ($element[options] as $key => $choice) { + if (is_array($choice)) { + $select .= '<optgroup label="'. $key .'">'; + foreach ($choice as $key => $choice) { + $select .= '<option value="'. $key .'"'. (is_array($elementp[value]) ? (in_array($key, $element[value]) ? ' selected="selected"' : '') : ($element[value] == $key ? ' selected="selected"' : '')) .'>'. check_plain($choice) .'</option>'; + } + $select .= '</optgroup>'; + } + else { + $select .= '<option value="'. $key .'"'. (is_array($element[value]) ? (in_array($key, $element[value]) ? ' selected="selected"' : '') : ($element[value] == $key ? ' selected="selected"' : '')) .'>'. check_plain($choice) .'</option>'; + } + } + return theme('form_element', $element[title], '<select name="'. $element[name] .''. ($element[multiple] ? '[]' : '') .'"'. ($element[multiple] ? ' multiple="multiple" ' : '') . ($element[extra] ? ' '. $element[extra] : '') .' id="' . $element[id] .'">'. $select .'</select>', $element[description], $element[name], $element[required], _form_get_error($element[name])); +} + +/** + * Format a group of form items. + * + * @param $element + * An associative array containing the properties of the element. + * Properties used : attributes, title, description, children, collapsible, collapsed + * @return + * A themed HTML string representing the form item group. + */ +function theme_fieldset($element) { + if ($element[collapsible]) { + drupal_add_js('misc/collapse.js'); + + $element[attributes]['class'] .= ' collapsible'; + if ($element[collapsed]) { + $element[attributes]['class'] .= ' collapsed'; + } + } + + return '<fieldset' . drupal_attributes($element[attributes]) .'>' . ($element[title] ? '<legend>'. $element[title] .'</legend>' : '') . $element[children] . $element[value] . ($element[description] ? '<div class="description">'. $element[description] .'</div>' : '') . "</fieldset>\n"; + +} + + +/** + * Format a radio button. + * + * @param $element + * An associative array containing the properties of the element. + * Properties used : required, return_value, value, attributes, title, description + * @return + * A themed HTML string representing the form item group. + */ +function theme_radio($element) { + $output = '<input type="radio" '; + $output .= 'class="'. _form_get_class('form-radio', $element[required], _form_get_error($element[name])) .'" '; + $output .= 'name="' . $element[name] .'" '; + $output .= 'value="'. $element[return_value] .'" '; + $output .= ($element[value] == $element[return_value]) ? ' checked="checked" ' : ' '; + $output .= drupal_attributes($element[attributes]) .' />'; + if (!is_null($element[title])) { + $output = '<label class="option">'. $output .' '. $element[title] .'</label>'; + } + return theme('form_element', NULL, $output, $element[description], $element[name], $element[required], _form_get_error($element[name])); +} + +/** + * Format a set of radio buttons. + * + * @param $element + * An associative array containing the properties of the element. + * Properties used : title, value, options, description, required and attributes. + * @return + * A themed HTML string representing the radio button set. + */ +function theme_radios($element) { + if ($element[title] || $element[description]) { + return theme('form_element', $element[title], $element[children], $element[description], $element[id], $element[required], _form_get_error($element[name])); + } + else { + return $element[children]; + } +} + +/** + * Format a set of radio buttons. + * + * @param $element + * An associative array containing the properties of the element. + * Properties used : title, value, options, description, required and attributes. + * @return + * A themed HTML string representing the radio button set. + */ +function theme_date($element) { + $output = '<div class="container-inline">' . $element[children] . '</div>'; + return theme('form_element', $element[title], $output, $element[description], $element[id], $element[required], _form_get_error($element[name])); +} + +/** + * Roll out a single checkbox element to a list of checkboxes, using the options array as index. + */ +function expand_date($element) { + // Default to current date + if (!isset($element[value])) { + $element[value] = array('day' => format_date(time(), 'custom', 'j'), + 'month' => format_date(time(), 'custom', 'n'), + 'year' => format_date(time(), 'custom', 'Y')); + } + + // Determine the order of day, month, year in the site's chosen date format. + $format = variable_get('date_format_short', 'm/d/Y'); + $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); + + // Output multi-selector for date + foreach ($order as $type) { + switch ($type) { + case 'day': + $options = drupal_map_assoc(range(1, 31)); + break; + case 'month': + $options = drupal_map_assoc(range(1, 12), '_profile_map_month'); + break; + case 'year': + $options = drupal_map_assoc(range(1900, 2050)); + break; + } + $element[$type] = array(type => 'radio', value => $element[value][$type], attributes => $element[attributes], parents => $element[parents], options => $options, tree => TRUE); + } + + return $element; +} + + +/** + * Roll out a single checkbox element to a list of checkboxes, using the options array as index. + */ +function expand_radios($element) { + if (count($element[options]) > 0) { + foreach ($element[options] as $key => $choice) { + if (!$element[$key]) { + $element[$key] = array(type => 'radio', title => $choice, return_value => $key, default_value => $element[default_value], attributes => $element[attributes], parents => $element[parents], spawned => TRUE); + } + } + } + + return $element; +} + + +/** + * Format a form item. + * + * @param $element + * An associative array containing the properties of the element. + * Properties used : title, value, description, required, error + * @return + * A themed HTML string representing the form item. + */ +function theme_item($element) { + return theme('form_element', $element[title], $element[value] . $element[children], $element[description], $element[id], $element[required], $element[error]); +} + + +/** + * Format a checkbox. + * + * @param $element + * An associative array containing the properties of the element. + * Properties used : title, value, return_value, description, required + * @return + * A themed HTML string representing the checkbox. + */ +function theme_checkbox($element) { + $checkbox = '<input '; + $checkbox .= 'type="checkbox" '; + $checkbox .= 'class="'. _form_get_class('form-checkbox', $element[required], _form_get_error($element[name])) . '" '; + $checkbox .= 'name="'. $element[name] .'" '; + $checkbox .= 'id="'. $element[id].'" ' ; + $checkbox .= 'value="'. $element[return_value] .'" '; + $checkbox .= ($element[value] == $element[return_value]) ? ' checked="checked" ' : ' '; + $checkbox .= drupal_attributes($element[attributes]) . ' />'; + + if (!is_null($element[title])) { + $checkbox = '<label class="option">'. $checkbox .' '. $element[title] .'</label>'; + } + + return theme('form_element', NULL, $checkbox, $element[description], $element[name], $element[required], _form_get_error($element[name])); +} + +/** + * 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. + */ +function theme_checkboxes($element) { + if ($element[title] || $element[description]) { + return theme('form_element', $element[title], $element[children], $element[description], 'edit-'. $element[name], $element[required], _form_get_error($element[name])); + } + else { + return $element[children]; + } +} + +function expand_checkboxes($element) { + $value = is_array($element[value]) ? $element[value] : array(); + if (count($element[options]) > 0) { + if (!isset($element[default_value]) || $element[default_value] == 0) { + $element[default_value] = array(); + } + foreach ($element[options] as $key => $choice) { + if (!isset($element[$key])) { + $element[$key] = array( + type => 'checkbox', processed => TRUE, title => $choice, tree => TRUE, + value => in_array($key, $value), attributes => $element[attributes] + ); + } + } + } + return $element; +} + + +function theme_submit($element) { + return theme('button', $element); +} + +function theme_button($element) { + return '<input type="submit" class="form-'. $element[button_type] .'" name="'. $element[name] .'" value="'. check_plain($element[value]) .'" '. drupal_attributes($element[attributes]) ." />\n"; +} + +/** + * Format a hidden form field. + * + * @param $element + * An associative array containing the properties of the element. + * Properties used : value, edit + * @return + * A themed HTML string representing the hidden form field. + */ +function theme_hidden($element) { + return '<input type="hidden" name="'. $element[name] . '" id="' . $element[id] . '" value="'. check_plain($element[value]) ."\" " . drupal_attributes($element[attributes]) ." />\n"; +} + +/** + * Format a textfield. + * + * @param $element + * An associative array containing the properties of the element. + * Properties used : title, value, description, size, maxlength, required, attributes autocomplete_path + * @return + * A themed HTML string representing the textfield. + */ +function theme_textfield($element) { + $size = $element[size] ? ' size="' . $element[size] . '"' : ''; + if ($element[autocomplete_path]) { + drupal_add_js('misc/autocomplete.js'); + $class = ' form-autocomplete'; + $extra = '<input class="autocomplete" type="hidden" id="'. $element[id] .'-autocomplete" value="'. check_url(url($element[autocomplete_path], NULL, NULL, TRUE)) .'" disabled="disabled" />'; + } + + $output = '<input type="text" maxlength="'. $element[maxlength] .'" class="'. _form_get_class("form-text$class", $element[required], _form_get_error($element[name])) .'" name="'. $element[name] .'" id="'. $element[id] .'" '. $size .' value="'. check_plain($element[value]) .'"'. drupal_attributes($element[attributes]) .' />'; + return theme('form_element', $element[title], $output, $element[description], $element[id], $element[required], _form_get_error($element[name])). $extra; +} + +/** + * Format a form. + * + * @param $element + * An associative array containing the properties of the element. + * Properties used : action, method, attributes, children + * @return + * A themed HTML string representing the form. + */ +function theme_form($element) { + // Anonymous div to satisfy XHTML compliancy. + $action = $element[action] ? 'action="' . check_url($element[action]) . '" ' : ''; + return '<form '. $action . ' method="'. $element[method] .'" '. drupal_attributes($element[attributes]) .">\n<div>". $element[children] ."\n</div></form>\n"; +} + + +/** + * Format a textarea. + * + * @param $element + * An associative array containing the properties of the element. + * Properties used : title, value, description, rows, cols, required, attributes + * @return + * A themed HTML string representing the textarea. + */ +function theme_textarea($element) { + $cols = $element[cols] ? ' cols="'. $element[cols] .'"' : ''; + + return theme('form_element', $element[title], '<textarea'. $cols .' rows="'. $element[rows] .'" name="'. $element[name] .'" id="' . $element[id] .'" class="'. _form_get_class('textarea', $element[required], _form_get_error($element[name])) .'"'. drupal_attributes($element[attributes]) .'>'. check_plain($element[value]) .'</textarea>', $element[description], $element[id], $element[required], _form_get_error($element[name])); +} + +/** + * 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. + * Properties used : prefix, value, children and suffix. + * @return + * A themed HTML string representing the HTML markup. + */ + +function theme_markup($element) { + return $element[value] . $element[children]; +} + + + +/** +* 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. +*/ +function theme_password($element) { + $size = $element[size] ? ' size="'. $element[size] .'" ' : ''; + + $output = '<input type="password" maxlength="'. $element[maxlength] .'" class="'. _form_get_class("form-text $class", $element[required], _form_get_error($element[name])) .'" name="'. $element[name] .'" id="'. $element[id] .'" '. $size . drupal_attributes($element[attributes]) .' />'; + + return theme('form_element', $element[title], $output, $element[description], $element[id], $element[required], _form_get_error($element[name])); +} + +/** + * Format a weight selection menu. + * + * @param $element + * An associative array containing the properties of the element. + * Properties used : title, delta, description + * @return + * A themed HTML string representing the form. + */ +function theme_weight($element) { + for ($n = (-1 * $element[delta]); $n <= $element[delta]; $n++) { + $weights[$n] = $n; + } + $element[options] = $weights; + $element[type] = 'select'; + + return form_render($element); +} + +/** + * File an error against the form element with the specified name. + */ +function form_set_error($name, $message) { + $GLOBALS['form'][$name] = $message; + drupal_set_message($message, 'error'); +} + +/** + * Return an associative array of all errors. + */ +function form_get_errors() { + if (array_key_exists('form', $GLOBALS)) { + return $GLOBALS['form']; + } +} + +/** + * 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. + * + * For assistance with handling the uploaded file correctly, see the API + * provided by file.inc. + */ +function theme_file($element) { + return theme('form_element', $element[title], '<input type="file" class="'. _form_get_class('form-file', $element[required], _form_get_error($element[name])) .'" name="'. $element[name] .'" id="'. form_clean_id($element[id]) .'" size="'. $element[size] ."\" />\n", $element[description], $element[id], $element[required], _form_get_error($element[name])); +} + +/** + * Return the error message filed against the form with the specified name. + */ +function _form_get_error($name) { + if (array_key_exists('form', $GLOBALS)) { + return $GLOBALS['form'][$name]; + } +} + +function _form_get_class($name, $required, $error) { + return $name. ($required ? ' required' : '') . ($error ? ' error' : ''); +} + +/** + * Remove invalid characters from an HTML ID attribute string + * + * @param $id + * The ID to clean + * @return + * The cleaned ID + */ +function form_clean_id($id = NULL) { + $id = str_replace('][', '-', $id); + return $id; +} + +/** + * @} End of "defgroup form". + */ + +?> |