Issue #1174938 by ericduran, aspilicious, voxpelli, David_Rothstein, effulgentsia: Added Natively support the HTML5 #required FAPI property.
parent
97674b9f05
commit
d672bcc401
|
@ -3104,6 +3104,19 @@ function form_pre_render_conditional_form_element($element) {
|
||||||
return $element;
|
return $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.
|
* Sets the #checked property of a checkbox element.
|
||||||
*/
|
*/
|
||||||
|
@ -4312,6 +4325,10 @@ function _form_set_class(&$element, $class = array()) {
|
||||||
// form_builder().
|
// form_builder().
|
||||||
if (!empty($element['#required'])) {
|
if (!empty($element['#required'])) {
|
||||||
$element['#attributes']['class'][] = '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)) {
|
if (isset($element['#parents']) && form_get_error($element)) {
|
||||||
$element['#attributes']['class'][] = 'error';
|
$element['#attributes']['class'][] = 'error';
|
||||||
|
|
|
@ -451,6 +451,29 @@ class FormsTestCase extends DrupalWebTestCase {
|
||||||
$this->drupalPost(NULL, array('checkboxes[one]' => TRUE, 'checkboxes[two]' => TRUE), t('Submit'));
|
$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.'));
|
$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';
|
$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
|
// Submit the form by pressing the 'Partial validate' button (uses
|
||||||
// #limit_validation_errors) and ensure that the title field is not
|
// #limit_validation_errors) and ensure that the title field is not
|
||||||
// validated, but the #element_validate handler for the 'test' field
|
// validated, but the #element_validate handler for the 'test' field
|
||||||
|
|
|
@ -229,6 +229,13 @@ function form_test_menu() {
|
||||||
'type' => MENU_CALLBACK,
|
'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;
|
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) {
|
function _form_test_checkboxes_zero_no_redirect($form, &$form_state) {
|
||||||
$form_state['redirect'] = FALSE;
|
$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;
|
||||||
|
}
|
||||||
|
|
|
@ -333,7 +333,7 @@ function system_element_info() {
|
||||||
'#button_type' => 'submit',
|
'#button_type' => 'submit',
|
||||||
'#executes_submit_callback' => TRUE,
|
'#executes_submit_callback' => TRUE,
|
||||||
'#limit_validation_errors' => FALSE,
|
'#limit_validation_errors' => FALSE,
|
||||||
'#process' => array('ajax_process_form'),
|
'#process' => array('form_process_button', 'ajax_process_form'),
|
||||||
'#theme_wrappers' => array('button'),
|
'#theme_wrappers' => array('button'),
|
||||||
);
|
);
|
||||||
$types['button'] = array(
|
$types['button'] = array(
|
||||||
|
@ -342,7 +342,7 @@ function system_element_info() {
|
||||||
'#button_type' => 'submit',
|
'#button_type' => 'submit',
|
||||||
'#executes_submit_callback' => FALSE,
|
'#executes_submit_callback' => FALSE,
|
||||||
'#limit_validation_errors' => FALSE,
|
'#limit_validation_errors' => FALSE,
|
||||||
'#process' => array('ajax_process_form'),
|
'#process' => array('form_process_button', 'ajax_process_form'),
|
||||||
'#theme_wrappers' => array('button'),
|
'#theme_wrappers' => array('button'),
|
||||||
);
|
);
|
||||||
$types['image_button'] = array(
|
$types['image_button'] = array(
|
||||||
|
@ -350,7 +350,7 @@ function system_element_info() {
|
||||||
'#button_type' => 'submit',
|
'#button_type' => 'submit',
|
||||||
'#executes_submit_callback' => TRUE,
|
'#executes_submit_callback' => TRUE,
|
||||||
'#limit_validation_errors' => FALSE,
|
'#limit_validation_errors' => FALSE,
|
||||||
'#process' => array('ajax_process_form'),
|
'#process' => array('form_process_button', 'ajax_process_form'),
|
||||||
'#return_value' => TRUE,
|
'#return_value' => TRUE,
|
||||||
'#has_garbage_value' => TRUE,
|
'#has_garbage_value' => TRUE,
|
||||||
'#src' => NULL,
|
'#src' => NULL,
|
||||||
|
|
Loading…
Reference in New Issue