reverted:
--- includes/common.inc 2010-10-03 20:17:25 +0000
+++ includes/common.inc 2010-10-03 05:11:16 +0000
@@ -5639,7 +5639,8 @@
if (is_int($property)) {
$property = '#' . $attribute;
}
+ // Do not overwrite already existing attributes.
+ if (isset($element[$property]) && !isset($element['#attributes'][$attribute])) {
- if (isset($element[$property])) {
$element['#attributes'][$attribute] = $element[$property];
}
}
diff -u includes/form.inc includes/form.inc
--- includes/form.inc 2010-10-03 20:17:25 +0000
+++ includes/form.inc 2010-10-03 18:09:53 +0000
@@ -1162,6 +1162,19 @@
}
}
}
+ // Non-multiple select fields always have a value in HTML. If the user
+ // does not change the form, it will be the value of the first option.
+ // Because of this, form validation for the field will almost always
+ // pass, even if the user did not select anything. To work around this
+ // browser behavior, required select fields without a #default_value get
+ // an additional, first empty option. In case the submitted value is
+ // identical to the empty option's value, we reset the element's value
+ // to NULL to trigger the regular #required handling below.
+ // @see form_process_select()
+ elseif ($elements['#type'] == 'select' && !$elements['#multiple'] && $elements['#required'] && !isset($elements['#default_value']) && $elements['#value'] === $elements['#empty_value']) {
+ $elements['#value'] = NULL;
+ form_set_value($elements, NULL, $form_state);
+ }
elseif (!isset($options[$elements['#value']])) {
form_error($elements, $t('An illegal choice has been detected. Please contact the site administrator.'));
watchdog('form', 'Illegal choice %choice in %name element.', array('%choice' => $elements['#value'], '%name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title']), WATCHDOG_ERROR);
@@ -1203,13 +1216,27 @@
}
// Make sure a value is passed when the field is required.
- // A simple call to empty() will not cut it here as some fields, like
- // checkboxes, can return a valid value of '0'. Instead, check the
- // length if it's a string, and the item count if it's an array.
- // An unchecked checkbox has a #value of integer 0, different than string
- // '0', which could be a valid value.
- if (isset($elements['#needs_validation']) && $elements['#required'] && (!count($elements['#value']) || (is_string($elements['#value']) && strlen(trim($elements['#value'])) == 0) || $elements['#value'] === 0)) {
- form_error($elements, $t('!name field is required.', array('!name' => $elements['#title'])));
+ if (isset($elements['#needs_validation']) && $elements['#required']) {
+ // A simple call to empty() will not cut it here as some fields, like
+ // checkboxes, can return a valid value of '0'. Instead, check the
+ // length if it's a string, and the item count if it's an array.
+ // An unchecked checkbox has a #value of integer 0, different than string
+ // '0', which could be a valid value.
+ $is_empty_multiple = (!count($elements['#value']));
+ $is_empty_string = (is_string($elements['#value']) && drupal_strlen(trim($elements['#value'])) == 0);
+ $is_empty_value = ($elements['#value'] === 0);
+ if ($is_empty_multiple || $is_empty_string || $is_empty_value) {
+ // Although discouraged, a #title is not mandatory for form elements. In
+ // case there is no #title, we cannot set a form error message.
+ // Instead of setting no #title, form constructors are encouraged to set
+ // #title_display to 'invisible' to improve accessibility.
+ if (isset($elements['#title'])) {
+ form_error($elements, $t('!name field is required.', array('!name' => $elements['#title'])));
+ }
+ else {
+ form_error($elements);
+ }
+ }
}
// Call user-defined form level validators.
@@ -2138,6 +2165,15 @@
return (isset($element['#default_value']) && is_array($element['#default_value'])) ? $element['#default_value'] : array();
}
}
+ // Non-multiple select elements may have an empty option preprended to them
+ // (see form_process_select()). When this occurs, usually #empty_value is
+ // an empty string, but some forms set #empty_value to integer 0 or some
+ // other non-string constant. PHP receives all submitted form input as
+ // strings, but if the empty option is selected, set the value to match the
+ // empty value exactly.
+ elseif (isset($element['#empty_value']) && $input === (string) $element['#empty_value']) {
+ return $element['#empty_value'];
+ }
else {
return $input;
}
@@ -2258,6 +2294,72 @@
}
/**
+ * Processes a select list form element.
+ *
+ * This process callback is mandatory for select fields, since all user agents
+ * automatically preselect the first available option of single (non-multiple)
+ * select lists.
+ *
+ * @param $element
+ * The form element to process. Properties used:
+ * - #multiple: (optional) Indicates whether one or more options can be
+ * selected. Defaults to FALSE.
+ * - #default_value: Must be NULL or not set in case there is no value for the
+ * element yet, in which case a first default option is inserted by default.
+ * Whether this first option is a valid option depends on whether the field
+ * is #required or not.
+ * - #required: (optional) Whether the user needs to select an option (TRUE)
+ * or not (FALSE). Defaults to FALSE.
+ * - #empty_option: (optional) The label to show for the first default option.
+ * By default, the label is automatically set to "- Please select -" for a
+ * required field and "- None -" for an optional field.
+ * - #empty_value: (optional) The value for the first default option, which is
+ * used to determine whether the user submitted a value or not.
+ * - If #required is TRUE, this defaults to '' (an empty string).
+ * - If #required is not TRUE and this value isn't set, then no extra option
+ * is added to the select control, leaving the control in a slightly
+ * illogical state, because there's no way for the user to select nothing,
+ * since all user agents automatically preselect the first available
+ * option. But people are used to this being the behavior of select
+ * controls.
+ * @todo Address the above issue in Drupal 8.
+ * - If #required is not TRUE and this value is set (most commonly to an
+ * empty string), then an extra option (see #empty_option above)
+ * representing a "non-selection" is added with this as its value.
+ *
+ * @see _form_validate()
+ */
+function form_process_select($element) {
+ // #multiple select fields need a special #name.
+ if ($element['#multiple']) {
+ $element['#attributes']['multiple'] = 'multiple';
+ $element['#attributes']['name'] = $element['#name'] . '[]';
+ }
+ // A non-#multiple select needs special handling to prevent user agents from
+ // preselecting the first option without intention. #multiple select lists do
+ // not get an empty option, as it would not make sense, user interface-wise.
+ else {
+ $required = $element['#required'];
+ // If the element is required and there is no #default_value, then add an
+ // empty option that will fail validation, so that the user is required to
+ // make a choice. Also, if there's a value for #empty_value or
+ // #empty_option, then add an option that represents emptiness.
+ if (($required && !isset($element['#default_value'])) || isset($element['#empty_value']) || isset($element['#empty_option'])) {
+ $element += array(
+ '#empty_value' => '',
+ '#empty_option' => $required ? t('- Select - ') : t('- None -'),
+ );
+ // The empty option is prepended to #options and purposively not merged
+ // to prevent another option in #options mistakenly using the same value
+ // as #empty_value.
+ $empty_option = array($element['#empty_value'] => $element['#empty_option']);
+ $element['#options'] = $empty_option + $element['#options'];
+ }
+ }
+ return $element;
+}
+
+/**
* Returns HTML for a select form element.
*
* It is possible to group options together; to do this, change the format of
@@ -2277,11 +2379,6 @@
element_set_attributes($element, array('id', 'name', 'size'));
_form_set_class($element, array('form-select'));
- if (!empty($element['#multiple'])) {
- $element['#attributes']['multiple'] = 'multiple';
- $element['#attributes']['name'] .= '[]';
- }
-
return '';
}
diff -u includes/install.core.inc includes/install.core.inc
--- includes/install.core.inc 2010-10-03 20:17:25 +0000
+++ includes/install.core.inc 2010-10-03 18:01:56 +0000
@@ -1756,11 +1756,10 @@
);
$countries = country_get_list();
- $countries = array_merge(array('' => st('No default country')), $countries);
$form['server_settings']['site_default_country'] = array(
'#type' => 'select',
'#title' => t('Default country'),
- '#default_value' => variable_get('site_default_country', ''),
+ '#default_value' => variable_get('site_default_country', NULL),
'#options' => $countries,
'#description' => st('Select the default country for the site.'),
'#weight' => 0,
diff -u modules/aggregator/aggregator.processor.inc modules/aggregator/aggregator.processor.inc
--- modules/aggregator/aggregator.processor.inc 2010-10-03 20:17:25 +0000
+++ modules/aggregator/aggregator.processor.inc 2010-10-03 18:01:56 +0000
@@ -70,7 +70,7 @@
function aggregator_form_aggregator_admin_form_alter(&$form, $form_state) {
if (in_array('aggregator', variable_get('aggregator_processors', array('aggregator')))) {
$info = module_invoke('aggregator', 'aggregator_process', 'info');
- $items = array(0 => t('none')) + drupal_map_assoc(array(3, 5, 10, 15, 20, 25), '_aggregator_items');
+ $items = drupal_map_assoc(array(3, 5, 10, 15, 20, 25), '_aggregator_items');
$period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 4838400, 9676800), 'format_interval');
$period[AGGREGATOR_CLEAR_NEVER] = t('Never');
@@ -90,8 +90,9 @@
$form['modules']['aggregator']['aggregator_summary_items'] = array(
'#type' => 'select',
- '#title' => t('Number of items shown in listing pages') ,
+ '#title' => t('Number of items shown in listing pages'),
'#default_value' => variable_get('aggregator_summary_items', 3),
+ '#empty_value' => 0,
'#options' => $items,
);
diff -u modules/block/block.admin.inc modules/block/block.admin.inc
--- modules/block/block.admin.inc 2010-10-03 20:17:25 +0000
+++ modules/block/block.admin.inc 2010-10-03 18:01:56 +0000
@@ -85,9 +85,6 @@
$block_regions = system_region_list($theme, REGIONS_VISIBLE);
}
- // We always add a region for disabled blocks.
- $block_regions += array(BLOCK_REGION_NONE => '<' . t('none') . '>');
-
// Weights range from -delta to +delta, so delta should be at least half
// of the amount of blocks present. This makes sure all blocks in the same
// region get an unique weight.
@@ -100,7 +97,8 @@
);
$form['block_regions'] = array(
'#type' => 'value',
- '#value' => $block_regions,
+ // Add a last region for disabled blocks.
+ '#value' => $block_regions + array(BLOCK_REGION_NONE => BLOCK_REGION_NONE),
);
$form['blocks'] = array();
$form['#tree'] = TRUE;
@@ -127,13 +125,14 @@
'#default_value' => $block['weight'],
'#delta' => $weight_delta,
'#title_display' => 'invisible',
- '#title' => t('Weight for @block block', array('%block' => $block['info'])),
+ '#title' => t('Weight for @block block', array('@block' => $block['info'])),
);
$form['blocks'][$key]['region'] = array(
'#type' => 'select',
- '#default_value' => $block['region'],
+ '#default_value' => $block['region'] != BLOCK_REGION_NONE ? $block['region'] : NULL,
+ '#empty_value' => BLOCK_REGION_NONE,
'#title_display' => 'invisible',
- '#title' => t('Region for @block block', array('%block' => $block['info'])),
+ '#title' => t('Region for @block block', array('@block' => $block['info'])),
'#options' => $block_regions,
);
$form['blocks'][$key]['configure'] = array(
@@ -150,7 +149,7 @@
}
}
// Do not allow disabling the main system content block.
- unset($form['blocks']['system_main']['region']['#options'][BLOCK_REGION_NONE]);
+ $form['blocks']['system_main']['region']['#required'] = TRUE;
$form['actions'] = array(
'#tree' => FALSE,
@@ -302,9 +301,9 @@
$form['regions'][$key] = array(
'#type' => 'select',
'#title' => $theme->info['name'],
- '#default_value' => (!empty($region) ? $region : BLOCK_REGION_NONE),
- '#options' => array(BLOCK_REGION_NONE => t('')) + system_region_list($key, REGIONS_VISIBLE),
- '#expandable' => ($key !== $theme_default),
+ '#default_value' => !empty($region) && $region != -1 ? $region : NULL,
+ '#empty_value' => BLOCK_REGION_NONE,
+ '#options' => system_region_list($key, REGIONS_VISIBLE),
'#weight' => ($key == $theme_default ? 9 : 10),
);
}
@@ -657,7 +656,7 @@
$block = &$variables['form']['blocks'][$i];
// Fetch the region for the current block.
- $region = $block['region']['#default_value'];
+ $region = (isset($block['region']['#default_value']) ? $block['region']['#default_value'] : BLOCK_REGION_NONE);
// Set special classes needed for table drag and drop.
$block['region']['#attributes']['class'] = array('block-region-select', 'block-region-' . $region);
diff -u modules/field_ui/field_ui.admin.inc modules/field_ui/field_ui.admin.inc
--- modules/field_ui/field_ui.admin.inc 2010-10-03 20:17:25 +0000
+++ modules/field_ui/field_ui.admin.inc 2010-10-03 18:01:56 +0000
@@ -304,7 +304,7 @@
t('Widget'),
array('data' => t('Operations'), 'colspan' => 2),
),
- '#parent_options' => array('' => t('')),
+ '#parent_options' => array(),
'#regions' => array(
'main' => array(),
'add_new' => array('title' => ' '),
@@ -432,8 +432,6 @@
$field_type_options = field_ui_field_type_options();
$widget_type_options = field_ui_widget_type_options(NULL, TRUE);
if ($field_type_options && $widget_type_options) {
- array_unshift($field_type_options, t('- Select a field type -'));
- array_unshift($widget_type_options, t('- Select a widget -'));
$name = '_add_new_field';
$table[$name] = array(
'#attributes' => array('class' => array('draggable', 'tabledrag-leaf', 'add-new')),
@@ -482,6 +480,7 @@
'type' => array(
'#type' => 'select',
'#options' => $field_type_options,
+ '#empty_option' => t('- Select a field type -'),
'#description' => t('Type of data to store.'),
'#attributes' => array('class' => array('field-type-select')),
'#prefix' => '