diff options
author | Dries Buytaert <dries@buytaert.net> | 2005-10-07 06:11:12 +0000 |
---|---|---|
committer | Dries Buytaert <dries@buytaert.net> | 2005-10-07 06:11:12 +0000 |
commit | 7e1527ee61bc10b3765b95b9af8faaa2254da5a8 (patch) | |
tree | 2225c7f571b4a3f635564f8281406a12b2a271a7 /includes | |
parent | 7b5b460534e5c54b07d28467c2aa2fc670c714e4 (diff) | |
download | brdo-7e1527ee61bc10b3765b95b9af8faaa2254da5a8.tar.gz brdo-7e1527ee61bc10b3765b95b9af8faaa2254da5a8.tar.bz2 |
- Patch #29465: new form API by Adrian et al.
TODO:
+ The contact.module was broken; a new patch for contact.module is needed.
+ Documentation is needed.
+ The most important modules need to be updated ASAP.
Diffstat (limited to 'includes')
-rw-r--r-- | includes/common.inc | 631 | ||||
-rw-r--r-- | includes/form.inc | 1078 | ||||
-rw-r--r-- | includes/legacy.inc | 584 | ||||
-rw-r--r-- | includes/locale.inc | 133 | ||||
-rw-r--r-- | includes/theme.inc | 49 | ||||
-rw-r--r-- | includes/unicode.inc | 4 |
6 files changed, 1754 insertions, 725 deletions
diff --git a/includes/common.inc b/includes/common.inc index eacb23a14..9ef5e6d7b 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -479,38 +479,6 @@ function fix_gpc_magic() { } /** - * An unchecked checkbox is not present in $_POST so we fix it here by - * proving a default value of 0. Also, with form_checkboxes() we expect - * an array, but HTML does not send the empty array. This is also taken - * care off. - */ -function fix_checkboxes() { - if (isset($_POST['form_array'])) { - $_POST['edit'] = _fix_checkboxes($_POST['edit'], $_POST['form_array'], array()); - } - if (isset($_POST['form_zero'])) { - $_POST['edit'] = _fix_checkboxes($_POST['edit'], $_POST['form_zero'], 0); - } -} - -function _fix_checkboxes($array1, $array2, $value) { - if (is_array($array2) && count($array2)) { - foreach ($array2 as $k => $v) { - if (is_array($v) && count($v)) { - $array1[$k] = _fix_checkboxes($array1[$k], $v, $value); - } - else if (!isset($array1[$k])) { - $array1[$k] = $value; - } - } - } - else { - $array1 = $value; - } - return $array1; -} - -/** * @name Conversion * @{ * Converts data structures to different types. @@ -549,6 +517,7 @@ function object2array($object) { return $array; } + /** * @} End of "Conversion". */ @@ -1000,600 +969,6 @@ function format_date($timestamp, $type = 'medium', $format = '', $timezone = NUL */ /** - * @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. - */ - -/** - * Generate a form from a set of form elements. - * - * @param $form - * An HTML string containing one or more form elements. - * @param $method - * The query method to use ("post" or "get"). - * @param $action - * The URL to send the form contents to, if not the current page. - * @param $attributes - * An associative array of attributes to add to the form tag. - * @result - * An HTML string with the contents of $form wrapped in a form tag. - */ -function form($form, $method = 'post', $action = NULL, $attributes = NULL) { - if (!$action) { - $action = request_uri(); - } - // Anonymous div to satisfy XHTML compliancy. - return '<form action="'. check_url($action) .'" method="'. $method .'"'. drupal_attributes($attributes) .">\n<div>". $form ."\n</div></form>\n"; -} - -/** - * Set a hidden 'form_token' field to be included in a form, used to validate - * that the resulting submission was actually generated by a local form. - * - * @param $key - * A unique key to identify the form that is currently being displayed. - * This identical key is later used to validate that the resulting submission - * actually originated with this form. - * @result - * A themed HTML string representing the hidden token field. - */ -function form_token($key) { - // this private key should always be kept secret - if (!variable_get('drupal_private_key', '')) { - variable_set('drupal_private_key', mt_rand()); - } - - // the verification token is an md5 hash of the form key and our private key - return form_hidden('form_token', md5($_SERVER['REMOTE_ADDR'] . $key . variable_get('drupal_private_key', ''))); -} - -/** - * Verify that the hidden 'form_token' field was actually generated with our - * private key. - * - * @param $edit - * An array containing the form that needs to be validated. - * @param $key - * The same key that was used to generate the 'form_token'. - * @param $error_message - * An optional error message to display if the form does not validate. - * @result - * There is nothing returned from this function, but if the 'form_token' does - * not validate an error is generated, preventing the submission. - */ -function form_validate($edit, $key, $error_message = NULL) { - if ($error_message == NULL) { - // set a generic default error message - $error = t('Validation error, please try again. If this error persists, please contact the site administrator.'); - } - - if ($edit['form_token'] != md5($_SERVER['REMOTE_ADDR'] . $key . variable_get('drupal_private_key', ''))) { - // setting this error will cause the form to fail validation - form_set_error('form_token', $error); - } -} - -/** - * 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']; - } -} - -/** - * 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' : ''); -} - -/** - * Format a general form item. - * - * @param $title - * The label for the form item. - * @param $value - * The contents of the form item. - * @param $description - * Explanatory text to display after the form item. - * @param $id - * A unique identifier for the form item. - * @param $required - * Whether the user must fill in this form element before submitting the form. - * @param $error - * An error message to display alongside the form element. - * @return - * A themed HTML string representing the form item. - */ -function form_item($title, $value, $description = NULL, $id = NULL, $required = FALSE, $error = FALSE) { - return theme('form_element', $title, $value, $description, $id, $required, $error); -} - -/** - * Format a group of form items. - * - * @param $legend - * The label for the form item group. - * @param $group - * The form items within the group, as an HTML string. - * @param $description - * Explanatory text to display after the form item group. - * @param $attributes - * An associative array of HTML attributes to add to the fieldset tag. - * @return - * A themed HTML string representing the form item group. - */ -function form_group($legend, $group, $description = NULL, $attributes = NULL) { - return '<fieldset' . drupal_attributes($attributes) .'>' . ($legend ? '<legend>'. $legend .'</legend>' : '') . $group . ($description ? '<div class="description">'. $description .'</div>' : '') . "</fieldset>\n"; -} - -/** - * Format a group of form items. - * - * @param $legend - * The label for the form item group. - * @param $group - * The form items within the group, as an HTML string. - * @param $collapsed - * A boolean value decided whether the group starts collapsed. - * @param $description - * Explanatory text to display after the form item group. - * @param $attributes - * An associative array of HTML attributes to add to the fieldset tag. - * @return - * A themed HTML string representing the form item group. - */ -function form_group_collapsible($legend, $group, $collapsed = FALSE, $description = NULL, $attributes = NULL) { - drupal_add_js('misc/collapse.js'); - - $attributes['class'] .= ' collapsible'; - if ($collapsed) { - $attributes['class'] .= ' collapsed'; - } - - return '<fieldset' . drupal_attributes($attributes) .'>' . ($legend ? '<legend>'. $legend .'</legend>' : '') . $group . ($description ? '<div class="description">'. $description .'</div>' : '') . "</fieldset>\n"; -} - -/** - * Format a radio button. - * - * @param $title - * The label for the radio button. - * @param $name - * The internal name used to refer to the button. - * @param $value - * The value that the form element takes on when selected. - * @param $checked - * Whether the button will be initially selected when the page is rendered. - * @param $description - * Explanatory text to display after the form item. - * @param $attributes - * An associative array of HTML attributes to add to the button. - * @param $required - * Whether the user must select this radio button before submitting the form. - * @return - * A themed HTML string representing the radio button. - */ -function form_radio($title, $name, $value = 1, $checked = FALSE, $description = NULL, $attributes = NULL, $required = FALSE) { - $element = '<input type="radio" class="'. _form_get_class('form-radio', $required, _form_get_error($name)) .'" name="edit['. $name .']" value="'. $value .'"'. ($checked ? ' checked="checked"' : '') . drupal_attributes($attributes) .' />'; - if (!is_null($title)) { - $element = '<label class="option">'. $element .' '. $title .'</label>'; - } - return theme('form_element', NULL, $element, $description, $name, $required, _form_get_error($name)); -} - -/** - * Format a set of radio buttons. - * - * @param $title - * The label for the radio buttons as a group. - * @param $name - * The internal name used to refer to the buttons. - * @param $value - * The currently selected radio button's key. - * @param $options - * An associative array of buttons to display. The keys in this array are - * button values, while the values are the labels to display for each button. - * @param $description - * Explanatory text to display after the form item. - * @param $required - * Whether the user must select a radio button before submitting the form. - * @param $attributes - * An associative array of HTML attributes to add to each button. - * @return - * A themed HTML string representing the radio button set. - */ -function form_radios($title, $name, $value, $options, $description = NULL, $required = FALSE, $attributes = NULL) { - if (count($options) > 0) { - $choices = ''; - foreach ($options as $key => $choice) { - $choices .= '<label class="option"><input type="radio" class="form-radio" name="edit['. $name .']" value="'. $key .'"'. ($key == $value ? ' checked="checked"' : ''). drupal_attributes($attributes) .' /> '. $choice .'</label><br />'; - } - return theme('form_element', $title, $choices, $description, NULL, $required, _form_get_error($name)); - } -} - -/** - * Format a checkbox. - * - * @param $title - * The label for the checkbox. - * @param $name - * The internal name used to refer to the button. - * @param $value - * The value that the form element takes on when selected. - * @param $checked - * Whether the button will be initially selected when the page is rendered. - * @param $description - * Explanatory text to display after the form item. - * @param $attributes - * An associative array of HTML attributes to add to the button. - * @param $required - * Whether the user must check this box before submitting the form. - * @return - * A themed HTML string representing the checkbox. - */ -function form_checkbox($title, $name, $value = 1, $checked = FALSE, $description = NULL, $attributes = NULL, $required = FALSE) { - $element = '<input type="checkbox" class="'. _form_get_class('form-checkbox', $required, _form_get_error($name)) .'" name="edit['. $name .']" id="edit-'. form_clean_id($name).'" value="'. $value .'"'. ($checked ? ' checked="checked"' : '') . drupal_attributes($attributes) .' />'; - if (!is_null($title)) { - $element = '<label class="option">'. $element .' '. $title .'</label>'; - } - return form_hidden($name, 1, 'form_zero') . theme('form_element', NULL, $element, $description, $name, $required, _form_get_error($name)); -} - -/** - * Format a set of checkboxes. - * - * @param $title - * The label for the checkboxes as a group. - * @param $name - * The internal name used to refer to the buttons. - * @param $values - * A linear array of keys of the initially checked boxes. - * @param $options - * An associative array of buttons to display. The keys in this array are - * button values, while the values are the labels to display for each button. - * @param $description - * Explanatory text to display after the form item. - * @param $attributes - * An associative array of HTML attributes to add to each button. - * @param $required - * Whether the user must check a box before submitting the form. - * @return - * A themed HTML string representing the checkbox set. - */ -function form_checkboxes($title, $name, $values, $options, $description = NULL, $attributes = NULL, $required = FALSE) { - if (count($options) > 0) { - if (!isset($values) || $values == 0) { - $values = array(); - } - $choices = ''; - foreach ($options as $key => $choice) { - $choices .= '<label class="option"><input type="checkbox" class="form-checkbox" name="edit['. $name .'][]" value="'. $key .'"'. (in_array($key, $values) ? ' checked="checked"' : ''). drupal_attributes($attributes) .' /> '. $choice .'</label><br />'; - } - return form_hidden($name, 1, 'form_array') . theme('form_element', $title, $choices, $description, NULL, $required, _form_get_error($name)); - } -} - -/** - * Format a single-line text field. - * - * @param $title - * The label for the text field. - * @param $name - * The internal name used to refer to the field. - * @param $value - * The initial value for the field at page load time. - * @param $size - * A measure of the visible size of the field (passed directly to HTML). - * @param $maxlength - * The maximum number of characters that may be entered in the field. - * @param $description - * Explanatory text to display after the form item. - * @param $attributes - * An associative array of HTML attributes to add to the form item. - * @param $required - * Whether the user must enter some text in the field. - * @return - * A themed HTML string representing the field. - */ -function form_textfield($title, $name, $value, $size, $maxlength, $description = NULL, $attributes = NULL, $required = FALSE) { - $size = $size ? ' size="'. $size .'"' : ''; - return theme('form_element', $title, '<input type="text" maxlength="'. $maxlength .'" class="'. _form_get_class('form-text', $required, _form_get_error($name)) .'" name="edit['. $name .']" id="edit-'. form_clean_id($name) .'"'. $size .' value="'. check_plain($value) .'"'. drupal_attributes($attributes) .' />', $description, 'edit-'. $name, $required, _form_get_error($name)); -} - -/** - * Format a single-line text field that uses Ajax for autocomplete. - * - * @param $title - * The label for the text field. - * @param $name - * The internal name used to refer to the field. - * @param $value - * The initial value for the field at page load time. - * @param $size - * A measure of the visible size of the field (passed directly to HTML). - * @param $maxlength - * The maximum number of characters that may be entered in the field. - * @param $callback_path - * A drupal path for the Ajax autocomplete callback. - * @param $description - * Explanatory text to display after the form item. - * @param $attributes - * An associative array of HTML attributes to add to the form item. - * @param $required - * Whether the user must enter some text in the field. - * @return - * A themed HTML string representing the field. - */ -function form_autocomplete($title, $name, $value, $size, $maxlength, $callback_path, $description = NULL, $attributes = NULL, $required = FALSE) { - drupal_add_js('misc/autocomplete.js'); - - $size = $size ? ' size="'. $size .'"' : ''; - - $output = theme('form_element', $title, '<input type="text" maxlength="'. $maxlength .'" class="'. _form_get_class('form-text form-autocomplete', $required, _form_get_error($name)) .'" name="edit['. $name .']" id="edit-'. form_clean_id($name) .'"'. $size .' value="'. check_plain($value) .'"'. drupal_attributes($attributes) .' />', $description, 'edit-'. $name, $required, _form_get_error($name)); - $output .= '<input class="autocomplete" type="hidden" id="edit-'. form_clean_id($name) .'-autocomplete" value="'. check_url(url($callback_path, NULL, NULL, TRUE)) .'" disabled="disabled" />'; - - return $output; -} - -/** - * Format a single-line text field that does not display its contents visibly. - * - * @param $title - * The label for the text field. - * @param $name - * The internal name used to refer to the field. - * @param $value - * The initial value for the field at page load time. - * @param $size - * A measure of the visible size of the field (passed directly to HTML). - * @param $maxlength - * The maximum number of characters that may be entered in the field. - * @param $description - * Explanatory text to display after the form item. - * @param $attributes - * An associative array of HTML attributes to add to the form item. - * @param $required - * Whether the user must enter some text in the field. - * @return - * A themed HTML string representing the field. - */ -function form_password($title, $name, $value, $size, $maxlength, $description = NULL, $attributes = NULL, $required = FALSE) { - $size = $size ? ' size="'. $size .'"' : ''; - return theme('form_element', $title, '<input type="password" class="'. _form_get_class('form-password', $required, _form_get_error($name)) .'" maxlength="'. $maxlength .'" name="edit['. $name .']" id="edit-'. form_clean_id($name) .'"'. $size .' value="'. check_plain($value) .'"'. drupal_attributes($attributes) .' />', $description, 'edit-'. $name, $required, _form_get_error($name)); -} - -/** - * Format a multiple-line text field. - * - * @param $title - * The label for the text field. - * @param $name - * The internal name used to refer to the field. - * @param $value - * The initial value for the field at page load time. - * @param $cols - * The width of the field, in columns of text. - * @param $rows - * The height of the field, in rows of text. - * @param $description - * Explanatory text to display after the form item. - * @param $attributes - * An associative array of HTML attributes to add to the form item. - * @param $required - * Whether the user must enter some text in the field. - * @return - * A themed HTML string representing the field. - */ -function form_textarea($title, $name, $value, $cols, $rows, $description = NULL, $attributes = NULL, $required = FALSE) { - $cols = $cols ? ' cols="'. $cols .'"' : ''; - $pre = ''; - $post = ''; - - // optionally plug in a WYSIWYG editor - foreach (module_list() as $module_name) { - if (module_hook($module_name, 'textarea')) { - $pre .= module_invoke($module_name, 'textarea', 'pre', $name); - $post .= module_invoke($module_name, 'textarea', 'post', $name); - } - } - - return theme('form_element', $title, $pre .'<textarea'. $cols .' rows="'. $rows .'" name="edit['. $name .']" id="edit-'. form_clean_id($name) .'" class="'. _form_get_class('textarea', $required, _form_get_error($name)) .'"'. drupal_attributes($attributes) .'>'. check_plain($value) .'</textarea>'. $post, $description, 'edit-'. $name, $required, _form_get_error($name)); -} - -/** - * Format a dropdown menu or scrolling selection box. - * - * @param $title - * The label for the form element. - * @param $name - * The internal name used to refer to the form element. - * @param $value - * The key of the currently selected item, or a linear array of keys of all the - * currently selected items if multiple selections are allowed. - * @param $options - * An associative array of buttons to display. The keys in this array are - * button values, while the values are the labels to display for each button. - * @param $description - * Explanatory text to display after the form item. - * @param $extra - * Additional HTML to inject into the select element tag. - * @param $multiple - * Whether the user may select more than one item. - * @param $required - * Whether the user must select a value before submitting the form. - * @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 form_select($title, $name, $value, $options, $description = NULL, $extra = 0, $multiple = FALSE, $required = FALSE) { - $select = ''; - foreach ($options as $key => $choice) { - if (is_array($choice)) { - $select .= '<optgroup label="'. $key .'">'; - foreach ($choice as $key => $choice) { - $select .= '<option value="'. $key .'"'. (is_array($value) ? (in_array($key, $value) ? ' selected="selected"' : '') : ($value == $key ? ' selected="selected"' : '')) .'>'. check_plain($choice) .'</option>'; - } - $select .= '</optgroup>'; - } - else { - $select .= '<option value="'. $key .'"'. (is_array($value) ? (in_array($key, $value) ? ' selected="selected"' : '') : ($value == $key ? ' selected="selected"' : '')) .'>'. check_plain($choice) .'</option>'; - } - } - return theme('form_element', $title, '<select name="edit['. $name .']'. ($multiple ? '[]' : '') .'"'. ($multiple ? ' multiple="multiple" ' : '') . ($extra ? ' '. $extra : '') .' id="edit-'. form_clean_id($name) .'">'. $select .'</select>', $description, 'edit-'. $name, $required, _form_get_error($name)); -} - -/** - * 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 form_file($title, $name, $size, $description = NULL, $required = FALSE) { - return theme('form_element', $title, '<input type="file" class="'. _form_get_class('form-file', $required, _form_get_error($name)) .'" name="edit['. $name .']" id="edit-'. form_clean_id($name) .'" size="'. $size ."\" />\n", $description, 'edit-'. $name, $required, _form_get_error($name)); -} - -/** - * Store data in a hidden form field. - * - * @param $name - * The internal name used to refer to the field. - * @param $value - * The stored data. - * @param $edit - * The array name to prefix to the $name. - * @param $attributes - * An array of HTML attributes for the input tag. - * @return - * A themed HTML string representing the hidden field. - * - * This function can be useful in retaining information between page requests, - * but be sure to validate the data on the receiving page as it is possible for - * an attacker to change the value before it is submitted. - */ -function form_hidden($name, $value, $edit = 'edit', $attributes = NULL) { - return '<input type="hidden" name="'. $edit .'['. $name .']" id="'. form_clean_id($edit .'-'. $name) .'" value="'. check_plain($value) .'"'. drupal_attributes($attributes) ." />\n"; -} - -/** - * Format an action button. - * - * @param $value - * Both the label for the button, and the value passed to the target page - * when this button is clicked. - * @param $name - * The internal name used to refer to the button. - * @param $type - * What type to pass to the HTML input tag. - * @param $attributes - * An associative array of HTML attributes to add to the form item. - * @return - * A themed HTML string representing the button. - */ -function form_button($value, $name = 'op', $type = 'submit', $attributes = NULL) { - return '<input type="'. $type .'" class="form-'. $type .'" name="'. $name .'" id="'. form_clean_id($name) .'" value="'. check_plain($value) .'" '. drupal_attributes($attributes) ." />\n"; -} - -/** - * Format a form submit button. - * - * @param $value - * Both the label for the button, and the value passed to the target page - * when this button is clicked. - * @param $name - * The internal name used to refer to the button. - * @param $attributes - * An associative array of HTML attributes to add to the form item. - * @return - * A themed HTML string representing the button. - */ -function form_submit($value, $name = 'op', $attributes = NULL) { - return form_button($value, $name, 'submit', $attributes); -} - -/** - * Format a weight selection menu. - * - * @param $title - * The label for the form element. - * @param $name - * The internal name used to refer to the form element. - * @param $value - * The selected weight value at page load time. - * @param $delta - * The largest in absolute value the weight can be. For example, if set to 10, - * weights could range from -10 to 10 inclusive. - * @param $description - * Explanatory text to display after the form item. - * @param $extra - * Additional HTML to inject into the select element tag. - * @return - * A themed HTML string representing the form element. - */ -function form_weight($title = NULL, $name = 'weight', $value = 0, $delta = 10, $description = NULL, $extra = 0) { - for ($n = (-1 * $delta); $n <= $delta; $n++) { - $weights[$n] = $n; - } - - return form_select($title, $name, $value, $weights, $description, $extra); -} - -/** - * 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". - */ - -/** * Generate an internal Drupal URL. * * @param $path @@ -1622,7 +997,7 @@ function url($path = NULL, $query = NULL, $fragment = NULL, $absolute = FALSE) { // Apache. $script = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') === false) ? 'index.php' : ''; } - + $path = drupal_get_path_alias($path); if (isset($fragment)) { @@ -1952,6 +1327,8 @@ function _drupal_bootstrap_full() { require_once './includes/file.inc'; require_once './includes/unicode.inc'; require_once './includes/image.inc'; + require_once './includes/form.inc'; + require_once './includes/legacy.inc'; // Set the Drupal custom error handler. set_error_handler('error_handler'); // Emit the correct charset HTTP header. 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". + */ + +?> diff --git a/includes/legacy.inc b/includes/legacy.inc new file mode 100644 index 000000000..ad17aeaa5 --- /dev/null +++ b/includes/legacy.inc @@ -0,0 +1,584 @@ +<? + +/** + * An unchecked checkbox is not present in $_POST so we fix it here by + * proving a default value of 0. Also, with form_checkboxes() we expect + * an array, but HTML does not send the empty array. This is also taken + * care off. + */ +function fix_checkboxes() { + if (isset($_POST['form_array'])) { + $_POST['edit'] = _fix_checkboxes($_POST['edit'], $_POST['form_array'], array()); + } + if (isset($_POST['form_zero'])) { + $_POST['edit'] = _fix_checkboxes($_POST['edit'], $_POST['form_zero'], 0); + } +} + +function _fix_checkboxes($array1, $array2, $value) { + if (is_array($array2) && count($array2)) { + foreach ($array2 as $k => $v) { + if (is_array($v) && count($v)) { + $array1[$k] = _fix_checkboxes($array1[$k], $v, $value); + } + else if (!isset($array1[$k])) { + $array1[$k] = $value; + } + } + } + else { + $array1 = $value; + } + return $array1; +} +/** + * @defgroup form Form generation (deprecated) + * @{ + * 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. + */ + +/** + * Generate a form from a set of form elements. + * + * @param $form + * An HTML string containing one or more form elements. + * @param $method + * The query method to use ("post" or "get"). + * @param $action + * The URL to send the form contents to, if not the current page. + * @param $attributes + * An associative array of attributes to add to the form tag. + * @result + * An HTML string with the contents of $form wrapped in a form tag. + */ +function form($form, $method = 'post', $action = NULL, $attributes = NULL) { + if (!$action) { + $action = request_uri(); + } + // Anonymous div to satisfy XHTML compliancy. + return '<form action="'. check_url($action) .'" method="'. $method .'"'. drupal_attributes($attributes) .">\n<div>". $form ."\n</div></form>\n"; +} +/** + * Format a general form item. + * + * @param $title + * The label for the form item. + * @param $value + * The contents of the form item. + * @param $description + * Explanatory text to display after the form item. + * @param $id + * A unique identifier for the form item. + * @param $required + * Whether the user must fill in this form element before submitting the form. + * @param $error + * An error message to display alongside the form element. + * @return + * A themed HTML string representing the form item. + */ +function form_item($title, $value, $description = NULL, $id = NULL, $required = FALSE, $error = FALSE) { + return theme('form_element', $title, $value, $description, $id, $required, $error); +} + +/** + * Format a group of form items. + * + * @param $legend + * The label for the form item group. + * @param $group + * The form items within the group, as an HTML string. + * @param $description + * Explanatory text to display after the form item group. + * @param $attributes + * An associative array of HTML attributes to add to the fieldset tag. + * @return + * A themed HTML string representing the form item group. + */ +function form_group($legend, $group, $description = NULL, $attributes = NULL) { + return '<fieldset' . drupal_attributes($attributes) .'>' . ($legend ? '<legend>'. $legend .'</legend>' : '') . $group . ($description ? '<div class="description">'. $description .'</div>' : '') . "</fieldset>\n"; +} + +/** + * Format a group of form items. + * + * @param $legend + * The label for the form item group. + * @param $group + * The form items within the group, as an HTML string. + * @param $collapsed + * A boolean value decided whether the group starts collapsed. + * @param $description + * Explanatory text to display after the form item group. + * @param $attributes + * An associative array of HTML attributes to add to the fieldset tag. + * @return + * A themed HTML string representing the form item group. + */ +function form_group_collapsible($legend, $group, $collapsed = FALSE, $description = NULL, $attributes = NULL) { + drupal_add_js('misc/collapse.js'); + + $attributes['class'] .= ' collapsible'; + if ($collapsed) { + $attributes['class'] .= ' collapsed'; + } + + return '<fieldset' . drupal_attributes($attributes) .'>' . ($legend ? '<legend>'. $legend .'</legend>' : '') . $group . ($description ? '<div class="description">'. $description .'</div>' : '') . "</fieldset>\n"; +} + +/** + * Format a radio button. + * + * @param $title + * The label for the radio button. + * @param $name + * The internal name used to refer to the button. + * @param $value + * The value that the form element takes on when selected. + * @param $checked + * Whether the button will be initially selected when the page is rendered. + * @param $description + * Explanatory text to display after the form item. + * @param $attributes + * An associative array of HTML attributes to add to the button. + * @param $required + * Whether the user must select this radio button before submitting the form. + * @return + * A themed HTML string representing the radio button. + */ +function form_radio($title, $name, $value = 1, $checked = FALSE, $description = NULL, $attributes = NULL, $required = FALSE) { + $element = '<input type="radio" class="'. _form_get_class('form-radio', $required, _form_get_error($name)) .'" name="edit['. $name .']" value="'. $value .'"'. ($checked ? ' checked="checked"' : '') . drupal_attributes($attributes) .' />'; + if (!is_null($title)) { + $element = '<label class="option">'. $element .' '. $title .'</label>'; + } + return theme('form_element', NULL, $element, $description, $name, $required, _form_get_error($name)); +} + +/** + * Format a set of radio buttons. + * + * @param $title + * The label for the radio buttons as a group. + * @param $name + * The internal name used to refer to the buttons. + * @param $value + * The currently selected radio button's key. + * @param $options + * An associative array of buttons to display. The keys in this array are + * button values, while the values are the labels to display for each button. + * @param $description + * Explanatory text to display after the form item. + * @param $required + * Whether the user must select a radio button before submitting the form. + * @param $attributes + * An associative array of HTML attributes to add to each button. + * @return + * A themed HTML string representing the radio button set. + */ +function form_radios($title, $name, $value, $options, $description = NULL, $required = FALSE, $attributes = NULL) { + if (count($options) > 0) { + $choices = ''; + foreach ($options as $key => $choice) { + $choices .= '<label class="option"><input type="radio" class="form-radio" name="edit['. $name .']" value="'. $key .'"'. ($key == $value ? ' checked="checked"' : ''). drupal_attributes($attributes) .' /> '. $choice .'</label><br />'; + } + return theme('form_element', $title, $choices, $description, NULL, $required, _form_get_error($name)); + } +} + +/** + * Format a checkbox. + * + * @param $title + * The label for the checkbox. + * @param $name + * The internal name used to refer to the button. + * @param $value + * The value that the form element takes on when selected. + * @param $checked + * Whether the button will be initially selected when the page is rendered. + * @param $description + * Explanatory text to display after the form item. + * @param $attributes + * An associative array of HTML attributes to add to the button. + * @param $required + * Whether the user must check this box before submitting the form. + * @return + * A themed HTML string representing the checkbox. + */ +function form_checkbox($title, $name, $value = 1, $checked = FALSE, $description = NULL, $attributes = NULL, $required = FALSE) { + $element = '<input type="checkbox" class="'. _form_get_class('form-checkbox', $required, _form_get_error($name)) .'" name="edit['. $name .']" id="edit-'. form_clean_id($name).'" value="'. $value .'"'. ($checked ? ' checked="checked"' : '') . drupal_attributes($attributes) .' />'; + if (!is_null($title)) { + $element = '<label class="option">'. $element .' '. $title .'</label>'; + } + return form_hidden($name, 1, 'form_zero') . theme('form_element', NULL, $element, $description, $name, $required, _form_get_error($name)); +} + +/** + * Format a set of checkboxes. + * + * @param $title + * The label for the checkboxes as a group. + * @param $name + * The internal name used to refer to the buttons. + * @param $values + * A linear array of keys of the initially checked boxes. + * @param $options + * An associative array of buttons to display. The keys in this array are + * button values, while the values are the labels to display for each button. + * @param $description + * Explanatory text to display after the form item. + * @param $attributes + * An associative array of HTML attributes to add to each button. + * @param $required + * Whether the user must check a box before submitting the form. + * @return + * A themed HTML string representing the checkbox set. + */ +function form_checkboxes($title, $name, $values, $options, $description = NULL, $attributes = NULL, $required = FALSE) { + if (count($options) > 0) { + if (!isset($values) || $values == 0) { + $values = array(); + } + $choices = ''; + foreach ($options as $key => $choice) { + $choices .= '<label class="option"><input type="checkbox" class="form-checkbox" name="edit['. $name .'][]" value="'. $key .'"'. (in_array($key, $values) ? ' checked="checked"' : ''). drupal_attributes($attributes) .' /> '. $choice .'</label><br />'; + } + return form_hidden($name, 1, 'form_array') . theme('form_element', $title, $choices, $description, NULL, $required, _form_get_error($name)); + } +} + +/** + * Format a single-line text field. + * + * @param $title + * The label for the text field. + * @param $name + * The internal name used to refer to the field. + * @param $value + * The initial value for the field at page load time. + * @param $size + * A measure of the visible size of the field (passed directly to HTML). + * @param $maxlength + * The maximum number of characters that may be entered in the field. + * @param $description + * Explanatory text to display after the form item. + * @param $attributes + * An associative array of HTML attributes to add to the form item. + * @param $required + * Whether the user must enter some text in the field. + * @return + * A themed HTML string representing the field. + */ +function form_textfield($title, $name, $value, $size, $maxlength, $description = NULL, $attributes = NULL, $required = FALSE) { + $size = $size ? ' size="'. $size .'"' : ''; + return theme('form_element', $title, '<input type="text" maxlength="'. $maxlength .'" class="'. _form_get_class('form-text', $required, _form_get_error($name)) .'" name="edit['. $name .']" id="edit-'. form_clean_id($name) .'"'. $size .' value="'. check_plain($value) .'"'. drupal_attributes($attributes) .' />', $description, 'edit-'. $name, $required, _form_get_error($name)); +} + +/** + * Format a single-line text field that uses Ajax for autocomplete. + * + * @param $title + * The label for the text field. + * @param $name + * The internal name used to refer to the field. + * @param $value + * The initial value for the field at page load time. + * @param $size + * A measure of the visible size of the field (passed directly to HTML). + * @param $maxlength + * The maximum number of characters that may be entered in the field. + * @param $callback_path + * A drupal path for the Ajax autocomplete callback. + * @param $description + * Explanatory text to display after the form item. + * @param $attributes + * An associative array of HTML attributes to add to the form item. + * @param $required + * Whether the user must enter some text in the field. + * @return + * A themed HTML string representing the field. + */ +function form_autocomplete($title, $name, $value, $size, $maxlength, $callback_path, $description = NULL, $attributes = NULL, $required = FALSE) { + drupal_add_js('misc/autocomplete.js'); + + $size = $size ? ' size="'. $size .'"' : ''; + + $output = theme('form_element', $title, '<input type="text" maxlength="'. $maxlength .'" class="'. _form_get_class('form-text form-autocomplete', $required, _form_get_error($name)) .'" name="edit['. $name .']" id="edit-'. form_clean_id($name) .'"'. $size .' value="'. check_plain($value) .'"'. drupal_attributes($attributes) .' />', $description, 'edit-'. $name, $required, _form_get_error($name)); + $output .= '<input class="autocomplete" type="hidden" id="edit-'. form_clean_id($name) .'-autocomplete" value="'. check_url(url($callback_path, NULL, NULL, TRUE)) .'" disabled="disabled" />'; + + return $output; +} + +/** + * Format a single-line text field that does not display its contents visibly. + * + * @param $title + * The label for the text field. + * @param $name + * The internal name used to refer to the field. + * @param $value + * The initial value for the field at page load time. + * @param $size + * A measure of the visible size of the field (passed directly to HTML). + * @param $maxlength + * The maximum number of characters that may be entered in the field. + * @param $description + * Explanatory text to display after the form item. + * @param $attributes + * An associative array of HTML attributes to add to the form item. + * @param $required + * Whether the user must enter some text in the field. + * @return + * A themed HTML string representing the field. + */ +function form_password($title, $name, $value, $size, $maxlength, $description = NULL, $attributes = NULL, $required = FALSE) { + $size = $size ? ' size="'. $size .'"' : ''; + return theme('form_element', $title, '<input type="password" class="'. _form_get_class('form-password', $required, _form_get_error($name)) .'" maxlength="'. $maxlength .'" name="edit['. $name .']" id="edit-'. form_clean_id($name) .'"'. $size .' value="'. check_plain($value) .'"'. drupal_attributes($attributes) .' />', $description, 'edit-'. $name, $required, _form_get_error($name)); +} + +/** + * Format a multiple-line text field. + * + * @param $title + * The label for the text field. + * @param $name + * The internal name used to refer to the field. + * @param $value + * The initial value for the field at page load time. + * @param $cols + * The width of the field, in columns of text. + * @param $rows + * The height of the field, in rows of text. + * @param $description + * Explanatory text to display after the form item. + * @param $attributes + * An associative array of HTML attributes to add to the form item. + * @param $required + * Whether the user must enter some text in the field. + * @return + * A themed HTML string representing the field. + */ +function form_textarea($title, $name, $value, $cols, $rows, $description = NULL, $attributes = NULL, $required = FALSE) { + $cols = $cols ? ' cols="'. $cols .'"' : ''; + $pre = ''; + $post = ''; + + // optionally plug in a WYSIWYG editor + foreach (module_list() as $module_name) { + if (module_hook($module_name, 'textarea')) { + $pre .= module_invoke($module_name, 'textarea', 'pre', $name); + $post .= module_invoke($module_name, 'textarea', 'post', $name); + } + } + + return theme('form_element', $title, $pre .'<textarea'. $cols .' rows="'. $rows .'" name="edit['. $name .']" id="edit-'. form_clean_id($name) .'" class="'. _form_get_class('textarea', $required, _form_get_error($name)) .'"'. drupal_attributes($attributes) .'>'. check_plain($value) .'</textarea>'. $post, $description, 'edit-'. $name, $required, _form_get_error($name)); +} + +/** + * Format a dropdown menu or scrolling selection box. + * + * @param $title + * The label for the form element. + * @param $name + * The internal name used to refer to the form element. + * @param $value + * The key of the currently selected item, or a linear array of keys of all the + * currently selected items if multiple selections are allowed. + * @param $options + * An associative array of buttons to display. The keys in this array are + * button values, while the values are the labels to display for each button. + * @param $description + * Explanatory text to display after the form item. + * @param $extra + * Additional HTML to inject into the select element tag. + * @param $multiple + * Whether the user may select more than one item. + * @param $required + * Whether the user must select a value before submitting the form. + * @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 form_select($title, $name, $value, $options, $description = NULL, $extra = 0, $multiple = FALSE, $required = FALSE) { + $select = ''; + foreach ($options as $key => $choice) { + if (is_array($choice)) { + $select .= '<optgroup label="'. $key .'">'; + foreach ($choice as $key => $choice) { + $select .= '<option value="'. $key .'"'. (is_array($value) ? (in_array($key, $value) ? ' selected="selected"' : '') : ($value == $key ? ' selected="selected"' : '')) .'>'. check_plain($choice) .'</option>'; + } + $select .= '</optgroup>'; + } + else { + $select .= '<option value="'. $key .'"'. (is_array($value) ? (in_array($key, $value) ? ' selected="selected"' : '') : ($value == $key ? ' selected="selected"' : '')) .'>'. check_plain($choice) .'</option>'; + } + } + return theme('form_element', $title, '<select name="edit['. $name .']'. ($multiple ? '[]' : '') .'"'. ($multiple ? ' multiple="multiple" ' : '') . ($extra ? ' '. $extra : '') .' id="edit-'. form_clean_id($name) .'">'. $select .'</select>', $description, 'edit-'. $name, $required, _form_get_error($name)); +} + +/** + * 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 form_file($title, $name, $size, $description = NULL, $required = FALSE) { + return theme('form_element', $title, '<input type="file" class="'. _form_get_class('form-file', $required, _form_get_error($name)) .'" name="edit['. $name .']" id="edit-'. form_clean_id($name) .'" size="'. $size ."\" />\n", $description, 'edit-'. $name, $required, _form_get_error($name)); +} + +/** + * Store data in a hidden form field. + * + * @param $name + * The internal name used to refer to the field. + * @param $value + * The stored data. + * @param $edit + * The array name to prefix to the $name. + * @param $attributes + * An array of HTML attributes for the input tag. + * @return + * A themed HTML string representing the hidden field. + * + * This function can be useful in retaining information between page requests, + * but be sure to validate the data on the receiving page as it is possible for + * an attacker to change the value before it is submitted. + */ +function form_hidden($name, $value, $edit = 'edit', $attributes = NULL) { + return '<input type="hidden" name="'. $edit .'['. $name .']" id="'. form_clean_id($edit .'-'. $name) .'" value="'. check_plain($value) .'"'. drupal_attributes($attributes) ." />\n"; +} + +/** + * Format an action button. + * + * @param $value + * Both the label for the button, and the value passed to the target page + * when this button is clicked. + * @param $name + * The internal name used to refer to the button. + * @param $type + * What type to pass to the HTML input tag. + * @param $attributes + * An associative array of HTML attributes to add to the form item. + * @return + * A themed HTML string representing the button. + */ +function form_button($value, $name = 'op', $type = 'submit', $attributes = NULL) { + return '<input type="'. $type .'" class="form-'. $type .'" name="'. $name .'" id="'. form_clean_id($name) .'" value="'. check_plain($value) .'" '. drupal_attributes($attributes) ." />\n"; +} + +/** + * Format a form submit button. + * + * @param $value + * Both the label for the button, and the value passed to the target page + * when this button is clicked. + * @param $name + * The internal name used to refer to the button. + * @param $attributes + * An associative array of HTML attributes to add to the form item. + * @return + * A themed HTML string representing the button. + */ +function form_submit($value, $name = 'op', $attributes = NULL) { + return form_button($value, $name, 'submit', $attributes); +} + +/** + * Format a weight selection menu. + * + * @param $title + * The label for the form element. + * @param $name + * The internal name used to refer to the form element. + * @param $value + * The selected weight value at page load time. + * @param $delta + * The largest in absolute value the weight can be. For example, if set to 10, + * weights could range from -10 to 10 inclusive. + * @param $description + * Explanatory text to display after the form item. + * @param $extra + * Additional HTML to inject into the select element tag. + * @return + * A themed HTML string representing the form element. + */ +function form_weight($title = NULL, $name = 'weight', $value = 0, $delta = 10, $description = NULL, $extra = 0) { + for ($n = (-1 * $delta); $n <= $delta; $n++) { + $weights[$n] = $n; + } + + return form_select($title, $name, $value, $weights, $description, $extra); +} + +/** + * Set a hidden 'form_token' field to be included in a form, used to validate + * that the resulting submission was actually generated by a local form. + * + * @param $key + * A unique key to identify the form that is currently being displayed. + * This identical key is later used to validate that the resulting submission + * actually originated with this form. + * @result + * A themed HTML string representing the hidden token field. + */ +function form_token($key) { + // this private key should always be kept secret + if (!variable_get('drupal_private_key', '')) { + variable_set('drupal_private_key', mt_rand()); + } + + // the verification token is an md5 hash of the form key and our private key + return form_hidden('form_token', md5($_SERVER['REMOTE_ADDR'] . $key . variable_get('drupal_private_key', ''))); +} + +/** + * Verify that the hidden 'form_token' field was actually generated with our + * private key. + * + * @param $edit + * An array containing the form that needs to be validated. + * @param $key + * The same key that was used to generate the 'form_token'. + * @param $error_message + * An optional error message to display if the form does not validate. + * @result + * There is nothing returned from this function, but if the 'form_token' does + * not validate an error is generated, preventing the submission. + */ +function form_validate($edit, $key, $error_message = NULL) { + if ($error_message == NULL) { + // set a generic default error message + $error = t('Validation error, please try again. If this error persists, please contact the site administrator.'); + } + + if ($edit['form_token'] != md5($_SERVER['REMOTE_ADDR'] . $key . variable_get('drupal_private_key', ''))) { + // setting this error will cause the form to fail validation + form_set_error('form_token', $error); + } +} + +/** + * @} End of "defgroup form". + */ + + diff --git a/includes/locale.inc b/includes/locale.inc index 0bacb47e3..8779a8c67 100644 --- a/includes/locale.inc +++ b/includes/locale.inc @@ -36,17 +36,22 @@ function _locale_add_language($code, $name, $onlylanguage = TRUE) { * User interface for the language management screen */ function _locale_admin_manage_screen() { - $edit = &$_POST['edit']; $languages = locale_supported_languages(TRUE, TRUE); - $header = array(array('data' => t('Code')), array('data' => t('English name')), array('data' => t('Enabled')), array('data' => t('Default')), array('data' => t('Translated')), array('data' => t('Operations'))); - + $options = array(); + $form[action] = url('admin/locale'); + $form['name'] = array(tree => TRUE); foreach ($languages['name'] as $key => $lang) { - + $options[$key] = ''; $status = db_fetch_object(db_query("SELECT isdefault, enabled FROM {locales_meta} WHERE locale = '%s'", $key)); - + if ($status->enabled) { + $enabled[] = $key; + } + if ($status->isdefault) { + $isdefault = $key; + } if ($key == 'en') { - $rows[] = array('en', check_plain($lang), form_checkbox('', 'enabled][en', 1, $status->enabled), form_radio('', 'sitedefault', $key, $status->isdefault), message_na(), ''); + $form['name']['en'] = array(type => 'markup', value => check_plain($lang)); } else { $original = db_fetch_object(db_query("SELECT COUNT(*) AS strings FROM {locales_source}")); @@ -54,11 +59,28 @@ function _locale_admin_manage_screen() { $ratio = ($original->strings > 0 && $translation->translation > 0) ? round(($translation->translation/$original->strings)*100., 2) : 0; - $rows[] = array(check_plain($key), ($key != 'en' ? form_textfield('', 'name]['. $key, $lang, 15, 64) : $lang), form_checkbox('', 'enabled]['. $key, 1, $status->enabled), form_radio('', 'sitedefault', $key, $status->isdefault), "$translation->translation/$original->strings ($ratio%)", ($key != 'en' ? l(t('delete'), 'admin/locale/language/delete/'. urlencode($key)) : '')); + $form['name'][$key] = array(type => 'textfield', default_value => $lang, size => 15, maxlength => 64); + $form['translation'][$key] = array(type => 'markup', default_value => "$translation->translation/$original->strings ($ratio%)"); } } + $form['enabled'] = array(type => 'checkboxes', options => $options, default_value => $enabled, return_value => 1); + $form['sitedefault'] = array(type => 'radios', options => $options, default_value => $isdefault, return_value => 1); + $form['submit'] = array(type => 'submit', value => t('Save configuration')); + + return drupal_get_form('_locale_admin_manage_screen', $form); +} - return form(theme('table', $header, $rows) . form_submit(t('Save configuration')), 'post', url('admin/locale')); +function theme__locale_admin_manage_screen($form) { + foreach ($form['name'] as $key => $element) { + // Don't take form control structures + if (is_array($element) && element_child($key)) { + $rows[] = array(check_plain($key), form_render($form['name'][$key]), form_render($form['enabled'][$key]), form_render($form['sitedefault'][$key]), ($key != 'en' ? form_render($form['translation'][$key]) : message_na()), ($key != 'en' ? l(t('delete'), 'admin/locale/language/delete/'. urlencode($key)) : '')); + } + } + $header = array(array('data' => t('Code')), array('data' => t('English name')), array('data' => t('Enabled')), array('data' => t('Default')), array('data' => t('Translated')), array('data' => t('Operations'))); + $output = theme('table', $header, $rows); + $output .= form_render($form); + return $output; } /** @@ -68,28 +90,30 @@ function _locale_admin_manage_add_screen() { $isocodes = _locale_prepare_iso_list(); - $output = '<h2>'. t('From language list') .'</h2>'; - $form = form_select(t('Language name'), 'langcode', key($isocodes), $isocodes, t('Select your language here, or add it below, if you are unable to find it.')); - $form .= form_submit(t('Add language')); - $output .= form($form); + $form = array(); + $form['header'] = array(prefix => '<h2>', value => t('Language list'), suffix => '</h2>'); + $form['langcode'] = array(type => 'select', title => t('Language name'), default_value => key($isocodes), options => $isocodes, description => t('Select your language here, or add it below, if you are unable to find it.')); + $form['submit'] = array(type => 'submit', value => t('Add language')); + $output = drupal_get_form('locale_add_language', $form); $edit = &$_POST['edit']; - $output .= '<h2>'. t('Custom language') .'</h2>'; - $form = form_textfield(t('Language code'), 'langcode', $edit['langcode'], 60, 12, t("Commonly this is an <a href=\"%iso-codes\">ISO 639 language code</a> with an optional country code for regional variants. Examples include 'en', 'en-US' and 'zh-cn'.", array('%iso-codes' => 'http://www.w3.org/WAI/ER/IG/ert/iso639.htm'))); - $form .= form_textfield(t('Language name in English'), 'langname', $edit['langname'], 60, 64, t('Name of the language. Will be available for translation in all languages.')); - $form .= form_submit(t('Add language')); - $output .= form($form); + $form = array(); + $form['header'] = array(prefix => '<h2>', value => t('Custom language') , suffix => '</h2>'); + $form['langcode'] = array(type => 'textfield', title => t('Language code'), default_value => $edit['langcode'], size => 12, maxlength => 60, description => t("Commonly this is an <a href=\"%iso-codes\">ISO 639 language code</a> with an optional country code for regional variants. Examples include 'en', 'en-US' and 'zh-cn'.", array('%iso-codes' => 'http://www.w3.org/WAI/ER/IG/ert/iso639.htm'))); + $form['langname'] = array(type => 'textfield', title => t('Language name in English'), default_value => $edit['langname'], size => 60, maxlength => 64, description => t('Name of the language. Will be available for translation in all languages.')); + $form['submit'] = array(type => 'submit', value => t('Add custom language')); + + $output .= drupal_get_form('_locale_custom_language', $form); return $output; } - /** * User interface for the translation import screen */ function _locale_admin_import_screen() { $languages = locale_supported_languages(FALSE, TRUE); - $languages = array_map("t", $languages['name']); + $languages = array_map('t', $languages['name']); unset($languages['en']); if (!count($languages)) { @@ -102,12 +126,15 @@ function _locale_admin_import_screen() { ); } - $form = form_file(t('Language file'), 'file', 50, t('A gettext Portable Object (.po) file.')); - $form .= form_select(t('Import into'), 'langcode', '', $languages, t('Choose the language you want to add strings into. If you choose a language which is not yet set up, then it will be added.')); - $form .= form_radios(t('Mode'), 'mode', 'overwrite', array('overwrite' => t('Strings in the uploaded file replace existing ones, new ones are added'), 'keep' => t('Existing strings are kept, only new strings are added'))); - $form .= form_submit(t('Import')); - $output = form($form, 'post', url('admin/locale/language/import'), array('enctype' => 'multipart/form-data')); - return $output; + $form = array(); + $form['file'] = array(type => 'file', title => t('Language file'), size => 50, description => t('A gettext Portable Object (.po) file.')); + $form['langcode'] = array(type => 'select', title => t('Import into'), options => $languages, description => t('Choose the language you want to add strings into. If you choose a language which is not yet set up, then it will be added.')); + $form['mode'] = array(type => 'radios', title => t('Mode'), default_value => 'overwrite', options => array('overwrite' => t('Strings in the uploaded file replace existing ones, new ones are added'), 'keep' => t('Existing strings are kept, only new strings are added'))); + $form['submit'] = array(type => 'submit', value => t('Import')); + $form[attributes]['enctype'] = 'multipart/form-data'; + $form[action] = 'admin/locale/language/import'; + + return drupal_get_form('_locale_admin_import', $form); } /** @@ -705,16 +732,18 @@ function _locale_admin_export_screen() { // Offer language specific export if any language is set up if (count($languages)) { $output .= '<h2>'. t('Export translation') .'</h2>'; - $form = form_select(t('Language name'), 'langcode', '', $languages, t('Select the language you would like to export in gettext Portable Object (.po) format.')); - $form .= form_submit(t('Export')); - $output .= form($form); + $form = array(); + $form['langcode'] = array(type => 'select', title => t('Language name'), options => $languages, description => t('Select the language you would like to export in gettext Portable Object (.po) format.')); + $form['submit'] = array(type => 'submit', value => t('Export')); + $output .= drupal_get_form('_locale_export_po', $form); } // Complete template export of the strings $output .= '<h2>'. t('Export template') .'</h2>'; - $form = t('<p>Generate a gettext Portable Object Template (.pot) file with all the interface strings from the Drupal locale database.</p>'); - $form .= form_submit(t('Export')); - $output .= form($form); + $output .= t('<p>Generate a gettext Portable Object Template (.pot) file with all the interface strings from the Drupal locale database.</p>'); + $form = array(); + $form['submit'] = array(type => 'submit', value => t('Export')); + $output .= drupal_get_form('_locale_export_pot', $form); return $output; } @@ -947,20 +976,24 @@ function _locale_string_edit($lid) { unset($languages['name']['en']); $result = db_query('SELECT DISTINCT s.source, t.translation, t.locale FROM {locales_source} s INNER JOIN {locales_target} t ON s.lid = t.lid WHERE s.lid = %d', $lid); - $form = ''; + $form = array(); while ($translation = db_fetch_object($result)) { $orig = $translation->source; - $form .= (strlen($orig) > 40) ? form_textarea($languages['name'][$translation->locale], $translation->locale, $translation->translation, 60, 15) : form_textfield($languages['name'][$translation->locale], $translation->locale, $translation->translation, 60, 128); + $form[$translation->locale] = (strlen($orig) > 40) ? + array(type => 'textarea', title => $languages['name'][$translation->locale], default_value => $translation->translation, cols => 60, rows => 15) + : array(type => 'textfield', title => $languages['name'][$translation->locale], default_value => $translation->translation, size => 60, maxlength => 128); unset($languages['name'][$translation->locale]); } + $form = array(type => 'item', title => t('Original text'), value => wordwrap(check_plain($orig, 0))); foreach ($languages['name'] as $key => $lang) { - $form .= (strlen($orig) > 40) ? form_textarea($lang, $key, '', 60, 15) : form_textfield($lang, $key, '', 60, 128); + $form[$key] = (strlen($orig) > 40) ? +array(type => 'textarea', title => $lang, cols => 60, rows => 15) : +array(type => 'textfield', title => $lang, size => 60, maxlength => 128); } - $form = form_item(t('Original text'), wordwrap(check_plain($orig, 0))) . $form; - $form .= form_submit(t('Save translations')); + $form['submit'] = array(type => 'submit', value => t('Save translations')); - return form($form); + return $form; } /** @@ -1065,9 +1098,12 @@ function _locale_string_seek() { } } - $output .= theme('table', $header, $rows); - - $output .= theme('pager', NULL, 50, 0, $request); + if (count($rows)) { + $output .= theme('table', $header, $rows); + } + if ($pager = theme('pager', NULL, 50, 0, $request)) { + $output .= $pager; + } } return $output; @@ -1085,14 +1121,15 @@ function _locale_string_seek_form() { // Present edit form preserving previous user settings $query = _locale_string_seek_query(); - $form .= form_textfield(t('Strings to search for'), 'string', $query->string, 30, 30, t('Leave blank to show all strings. The search is case sensitive.')); - $form .= form_radios(t('Language'), 'language', ($query->language ? $query->language : 'all'), array_merge(array('all' => t('All languages'), 'en' => t('English (provided by Drupal)')), $languages['name'])); - $form .= form_radios(t('Search in'), 'searchin', ($query->searchin ? $query->searchin : 'all'), array('all' => t('All strings in that language'), 'translated' => t('Only translated strings'), 'untranslated' => t('Only untranslated strings'))); - - $form .= form_submit(t('Search')); - $output = form(form_group(t('Search strings'), $form), 'post', url('admin/locale/string/search')); - - return $output; + $form = array(); + $form['search'] = array(type => 'fieldset', title => t('Search')); + $form['search']['string'] = array(type => 'textfield', title => t('Strings to search for'), default_value => $query->string, size => 30, maxlength => 30, description => t('Leave blank to show all strings. The search is case sensitive.')); + $form['search']['language'] = array(type => 'radios', title => t('Language'), default_value => ($query->language ? $query->language : 'all'), options => array_merge(array('all' => t('All languages'), 'en' => t('English (provided by Drupal)')), $languages['name'])); + $form['search']['searchin'] = array(type => 'radios', title => t('Search in'), default_value => ($query->searchin ? $query->searchin : 'all'), options => array('all' => t('All strings in that language'), 'translated' => t('Only translated strings'), 'untranslated' => t('Only untranslated strings'))); + $form['search']['submit'] = array(type => 'submit', value => t('Search')); + $form[action] = 'admin/locale/string/search'; + + return drupal_get_form('_locale_string_seek', $form); } // --------------------------------------------------------------------------------- diff --git a/includes/theme.inc b/includes/theme.inc index 2f3e64b6f..ba2051ff7 100644 --- a/includes/theme.inc +++ b/includes/theme.inc @@ -959,55 +959,6 @@ function theme_blocks($region) { } /** - * Output a confirmation form - * - * This function outputs a complete form for confirming an action. A link is - * offered to go back to the item that is being changed in case the user changes - * his/her mind. - * - * You should use $_POST['edit'][$name] (where $name is usually 'confirm') to - * check if the confirmation was successful. - * - * @param $question - * The question to ask the user (e.g. "Are you sure you want to delete the - * block <em>foo</em>?"). - * @param $path - * The page to go to if the user denies the action. - * @param $description - * Additional text to display (defaults to "This action cannot be undone."). - * @param $yes - * A caption for the button which confirms the action (e.g. "Delete", - * "Replace", ...). - * @param $no - * A caption for the link which denies the action (e.g. "Cancel"). - * @param $extra - * Additional HTML to inject into the form, for example form_hidden()s. - * @param $name - * The internal name used to refer to the confirmation item. - * @return - * A themed HTML string representing the form. - */ -function theme_confirm($question, $path, $description = NULL, $yes = NULL, $no = NULL, $extra = NULL, $name = 'confirm') { - drupal_set_title($question); - - if (is_null($description)) { - $description = t('This action cannot be undone.'); - } - - $output .= '<p>'. $description ."</p>\n"; - if (!is_null($extra)) { - $output .= $extra; - } - $output .= '<div class="container-inline">'; - $output .= form_submit($yes ? $yes : t('Confirm')); - $output .= l($no ? $no : t('Cancel'), $path); - $output .= "</div>\n"; - - $output .= form_hidden($name, 1); - return form($output, 'post', NULL, array('class' => 'confirmation')); -} - -/** * Format a username. * * @param $object diff --git a/includes/unicode.inc b/includes/unicode.inc index 04751ed79..ce6ba32ac 100644 --- a/includes/unicode.inc +++ b/includes/unicode.inc @@ -81,7 +81,8 @@ function unicode_settings() { $options = array(UNICODE_SINGLEBYTE => t('Standard PHP: operations on Unicode strings are emulated on a best-effort basis. Install the <a href="%url">PHP mbstring extension</a> for improved Unicode support.', array('%url' => 'http://www.php.net/mbstring')), UNICODE_MULTIBYTE => t('Multi-byte: operations on Unicode strings are supported through the <a href="%url">PHP mbstring extension</a>.', array('%url' => 'http://www.php.net/mbstring')), UNICODE_ERROR => t('Invalid: the current configuration is incompatible with Drupal.')); - return form_item(t('String handling method'), $options[$status]); + $form['settings'] = array(type => 'item', title =>t('String handling method'), value => $options[$status]); + return $form; } /** @@ -474,3 +475,4 @@ function drupal_substr($text, $start, $length = NULL) { } } + |