summaryrefslogtreecommitdiff
path: root/includes/form.inc
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2010-10-28 02:20:14 +0000
committerDries Buytaert <dries@buytaert.net>2010-10-28 02:20:14 +0000
commit0344a78d9643d97e1aff8ab94fec551bc091bfbc (patch)
tree1baef104d17fbe810f4460abf4b853e49bbd5a1a /includes/form.inc
parent25bc5f030d30a391344e215fe1adb434d52d39ee (diff)
downloadbrdo-0344a78d9643d97e1aff8ab94fec551bc091bfbc.tar.gz
brdo-0344a78d9643d97e1aff8ab94fec551bc091bfbc.tar.bz2
- Patch #654796 by chx, c960657, sun, effulgentsia: fix bugs with checkbox element.
Diffstat (limited to 'includes/form.inc')
-rw-r--r--includes/form.inc66
1 files changed, 59 insertions, 7 deletions
diff --git a/includes/form.inc b/includes/form.inc
index 930f8b512..8bf2ba072 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -2073,11 +2073,29 @@ function form_type_image_button_value($form, $input, $form_state) {
* for this element. Return nothing to use the default.
*/
function form_type_checkbox_value($element, $input = FALSE) {
- if ($input !== FALSE) {
- // Successful (checked) checkboxes are present with a value (possibly '0').
- // http://www.w3.org/TR/html401/interact/forms.html#successful-controls
- // For an unchecked checkbox, we return integer 0, so we can explicitly
- // test for a value different than string '0'.
+ if ($input === FALSE) {
+ // Use #default_value as the default value of a checkbox, except change
+ // NULL to 0, because _form_builder_handle_input_element() would otherwise
+ // replace NULL with empty string, but an empty string is a potentially
+ // valid value for a checked checkbox.
+ return isset($element['#default_value']) ? $element['#default_value'] : 0;
+ }
+ else {
+ // Checked checkboxes are submitted with a value (possibly '0' or ''):
+ // http://www.w3.org/TR/html401/interact/forms.html#successful-controls.
+ // For checked checkboxes, browsers submit the string version of
+ // #return_value, but we return the original #return_value. For unchecked
+ // checkboxes, browsers submit nothing at all, but
+ // _form_builder_handle_input_element() detects this, and calls this
+ // function with $input=NULL. Returning NULL from a value callback means to
+ // use the default value, which is not what is wanted when an unchecked
+ // checkbox is submitted, so we use integer 0 as the value indicating an
+ // unchecked checkbox. Therefore, modules must not use integer 0 as a
+ // #return_value, as doing so results in the checkbox always being treated
+ // as unchecked. The string '0' is allowed for #return_value. The most
+ // common use-case for setting #return_value to either 0 or '0' is for the
+ // first option within a 0-indexed array of checkboxes, and for this,
+ // form_process_checkboxes() uses the string rather than the integer.
return isset($input) ? $element['#return_value'] : 0;
}
}
@@ -2109,7 +2127,7 @@ function form_type_checkboxes_value($element, $input = FALSE) {
// NULL elements from the array before constructing the return value, to
// simulate the behavior of web browsers (which do not send unchecked
// checkboxes to the server at all). This will not affect non-programmatic
- // form submissions, since a checkbox can never legitimately be NULL.
+ // form submissions, since all values in $_POST are strings.
foreach ($input as $key => $value) {
if (!isset($value)) {
unset($input[$key]);
@@ -2807,7 +2825,7 @@ function theme_checkbox($variables) {
element_set_attributes($element, array('id', 'name', '#return_value' => 'value'));
// Unchecked checkbox has #value of integer 0.
- if (isset($element['#return_value']) && isset($element['#value']) && $element['#value'] !== 0 && $element['#value'] == $element['#return_value']) {
+ if (!empty($element['#checked'])) {
$element['#attributes']['checked'] = 'checked';
}
_form_set_class($element, array('form-checkbox'));
@@ -2859,6 +2877,33 @@ function form_pre_render_conditional_form_element($element) {
return $element;
}
+/**
+ * Sets the #checked property of a checkbox element.
+ */
+function form_process_checkbox($element, $form_state) {
+ $value = $element['#value'];
+ $return_value = $element['#return_value'];
+ // On form submission, the #value of an available and enabled checked
+ // checkbox is #return_value, and the #value of an available and enabled
+ // unchecked checkbox is integer 0. On not submitted forms, and for
+ // checkboxes with #access=FALSE or #disabled=TRUE, the #value is
+ // #default_value (integer 0 if #default_value is NULL). Most of the time,
+ // a string comparison of #value and #return_value is sufficient for
+ // determining the "checked" state, but a value of TRUE always means checked
+ // (even if #return_value is 'foo'), and a value of FALSE or integer 0 always
+ // means unchecked (even if #return_value is '' or '0').
+ if ($value === TRUE || $value === FALSE || $value === 0) {
+ $element['#checked'] = (bool) $value;
+ }
+ else {
+ // Compare as strings, so that 15 is not considered equal to '15foo', but 1
+ // is considered equal to '1'. This cast does not imply that either #value
+ // or #return_value is expected to be a string.
+ $element['#checked'] = ((string) $value === (string) $return_value);
+ }
+ return $element;
+}
+
function form_process_checkboxes($element) {
$value = is_array($element['#value']) ? $element['#value'] : array();
$element['#tree'] = TRUE;
@@ -2868,6 +2913,13 @@ function form_process_checkboxes($element) {
}
foreach ($element['#options'] as $key => $choice) {
if (!isset($element[$key])) {
+ // Integer 0 is not a valid #return_value, so use '0' instead.
+ // @see form_type_checkbox_value().
+ // @todo For Drupal 8, cast all integer keys to strings for consistency
+ // with form_process_radios().
+ if ($key === 0) {
+ $key = '0';
+ }
$element[$key] = array(
'#type' => 'checkbox',
'#processed' => TRUE,