summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcatch2012-03-27 06:23:35 (GMT)
committercatch2012-03-27 06:23:35 (GMT)
commitd672bcc4019552f987d1fa6887b42aaa64e43967 (patch)
tree541bef247c90245df542fc058984e0f762e5a852
parent97674b9f05fa2b911bf0b985e49a1e0fd0420711 (diff)
Issue #1174938 by ericduran, aspilicious, voxpelli, David_Rothstein, effulgentsia: Added Natively support the HTML5 #required FAPI property.
-rw-r--r--core/includes/form.inc17
-rw-r--r--core/modules/simpletest/tests/form.test42
-rw-r--r--core/modules/simpletest/tests/form_test.module22
-rw-r--r--core/modules/system/system.module6
4 files changed, 84 insertions, 3 deletions
diff --git a/core/includes/form.inc b/core/includes/form.inc
index 35acd84..65c462a 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -3105,6 +3105,19 @@ function form_pre_render_conditional_form_element($element) {
}
/**
+ * Processes a form button element.
+ */
+function form_process_button($element, $form_state) {
+ // If this is a button intentionally allowing incomplete form submission
+ // (e.g., a "Previous" or "Add another item" button), then also skip
+ // client-side validation.
+ if (isset($element['#limit_validation_errors']) && $element['#limit_validation_errors'] !== FALSE) {
+ $element['#attributes']['formnovalidate'] = 'formnovalidate';
+ }
+ return $element;
+}
+
+/**
* Sets the #checked property of a checkbox element.
*/
function form_process_checkbox($element, $form_state) {
@@ -4312,6 +4325,10 @@ function _form_set_class(&$element, $class = array()) {
// form_builder().
if (!empty($element['#required'])) {
$element['#attributes']['class'][] = 'required';
+ // @todo Rename the _form_set_class() function to reflect that we're setting
+ // non-class attributes too.
+ $element['#attributes']['required'] = 'required';
+ $element['#attributes']['aria-required'] = 'true';
}
if (isset($element['#parents']) && form_get_error($element)) {
$element['#attributes']['class'][] = 'error';
diff --git a/core/modules/simpletest/tests/form.test b/core/modules/simpletest/tests/form.test
index c51d3e6..e79983c 100644
--- a/core/modules/simpletest/tests/form.test
+++ b/core/modules/simpletest/tests/form.test
@@ -451,6 +451,29 @@ class FormsTestCase extends DrupalWebTestCase {
$this->drupalPost(NULL, array('checkboxes[one]' => TRUE, 'checkboxes[two]' => TRUE), t('Submit'));
$this->assertText('An illegal choice has been detected.', t('Input forgery was detected.'));
}
+
+ /**
+ * Tests required attribute.
+ */
+ function testRequiredAttribute() {
+ $this->drupalGet('form-test/required-attribute');
+ $expected = 'required';
+ // Test to make sure the elements have the proper required attribute.
+ foreach (array('textfield', 'password') as $type) {
+ $element = $this->xpath('//input[@id=:id and @required=:expected]', array(
+ ':id' => 'edit-' . $type,
+ ':expected' => $expected,
+ ));
+ $this->assertTrue(!empty($element), t('The @type has the proper required attribute.', array('@type' => $type)));
+ }
+
+ // Test to make sure textarea has the proper required attribute.
+ $element = $this->xpath('//textarea[@id=:id and @required=:expected]', array(
+ ':id' => 'edit-textarea',
+ ':expected' => $expected,
+ ));
+ $this->assertTrue(!empty($element), t('The textarea has the proper required attribute.'));
+ }
}
/**
@@ -633,6 +656,25 @@ class FormValidationTestCase extends DrupalWebTestCase {
);
$path = 'form-test/limit-validation-errors';
+ // Render the form, and verify that the buttons with limited server-side
+ // validation have the proper 'formnovalidate' attribute (to prevent
+ // client-side validation by the browser).
+ $this->drupalGet($path);
+ $expected = 'formnovalidate';
+ foreach (array('partial', 'partial-numeric-index', 'substring') as $type) {
+ $element = $this->xpath('//input[@id=:id and @formnovalidate=:expected]', array(
+ ':id' => 'edit-' . $type,
+ ':expected' => $expected,
+ ));
+ $this->assertTrue(!empty($element), t('The @type button has the proper formnovalidate attribute.', array('@type' => $type)));
+ }
+ // The button with full server-side validation should not have the
+ // 'formnovalidate' attribute.
+ $element = $this->xpath('//input[@id=:id and not(@formnovalidate)]', array(
+ ':id' => 'edit-full',
+ ));
+ $this->assertTrue(!empty($element), t('The button with full server-side validation does not have the formnovalidate attribute.'));
+
// Submit the form by pressing the 'Partial validate' button (uses
// #limit_validation_errors) and ensure that the title field is not
// validated, but the #element_validate handler for the 'test' field
diff --git a/core/modules/simpletest/tests/form_test.module b/core/modules/simpletest/tests/form_test.module
index cddd9a6..3dcd247 100644
--- a/core/modules/simpletest/tests/form_test.module
+++ b/core/modules/simpletest/tests/form_test.module
@@ -229,6 +229,13 @@ function form_test_menu() {
'type' => MENU_CALLBACK,
);
+ $items['form-test/required-attribute'] = array(
+ 'title' => 'Required',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('form_test_required_attribute'),
+ 'access callback' => TRUE,
+ );
+
return $items;
}
@@ -1830,3 +1837,18 @@ function form_test_checkboxes_zero($form, &$form_state, $json = TRUE) {
function _form_test_checkboxes_zero_no_redirect($form, &$form_state) {
$form_state['redirect'] = FALSE;
}
+
+/**
+ * Builds a form to test the required attribute.
+ */
+function form_test_required_attribute($form, &$form_state) {
+ foreach (array('textfield', 'textarea', 'password') as $type) {
+ $form[$type] = array(
+ '#type' => $type,
+ '#required' => TRUE,
+ '#title' => $type,
+ );
+ }
+
+ return $form;
+}
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index e66202e..e6d0972 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -333,7 +333,7 @@ function system_element_info() {
'#button_type' => 'submit',
'#executes_submit_callback' => TRUE,
'#limit_validation_errors' => FALSE,
- '#process' => array('ajax_process_form'),
+ '#process' => array('form_process_button', 'ajax_process_form'),
'#theme_wrappers' => array('button'),
);
$types['button'] = array(
@@ -342,7 +342,7 @@ function system_element_info() {
'#button_type' => 'submit',
'#executes_submit_callback' => FALSE,
'#limit_validation_errors' => FALSE,
- '#process' => array('ajax_process_form'),
+ '#process' => array('form_process_button', 'ajax_process_form'),
'#theme_wrappers' => array('button'),
);
$types['image_button'] = array(
@@ -350,7 +350,7 @@ function system_element_info() {
'#button_type' => 'submit',
'#executes_submit_callback' => TRUE,
'#limit_validation_errors' => FALSE,
- '#process' => array('ajax_process_form'),
+ '#process' => array('form_process_button', 'ajax_process_form'),
'#return_value' => TRUE,
'#has_garbage_value' => TRUE,
'#src' => NULL,