Issue by Niklas Fiekas, ericduran: Added Support the #pattern FAPI property for native HTML5 pattern attribute.

8.0.x
catch 2012-05-08 12:00:06 +09:00
parent bd30dbfc09
commit a82955bfd5
4 changed files with 155 additions and 5 deletions
core
includes
modules/system

View File

@ -3213,6 +3213,56 @@ function form_process_actions($element, &$form_state) {
return $element;
}
/**
* #process callback for #pattern form element property.
*
* @param $element
* An associative array containing the properties and children of the
* generic input element.
* @param $form_state
* The $form_state array for the form this element belongs to.
*
* @return
* The processed element.
*
* @see form_validate_pattern()
*/
function form_process_pattern($element, &$form_state) {
if (isset($element['#pattern']) && !isset($element['#attributes']['pattern'])) {
$element['#attributes']['pattern'] = $element['#pattern'];
$element['#element_validate'][] = 'form_validate_pattern';
}
return $element;
}
/**
* #element_validate callback for #pattern form element property.
*
* @param $element
* An associative array containing the properties and children of the
* generic form element.
* @param $form_state
* The $form_state array for the form this element belongs to.
*
* @see form_process_pattern()
*/
function form_validate_pattern($element, &$form_state) {
if ($element['#value'] !== '') {
// The pattern must match the entire string and should have the same
// behavior as the RegExp object in ECMA 262.
// - Use bracket-style delimiters to avoid introducing a special delimiter
// character like '/' that would have to be escaped.
// - Put in brackets so that the pattern can't interfere with what's
// prepended and appended.
$pattern = '{^(?:' . $element['#pattern'] . ')$}';
if (!preg_match($pattern, $element['#value'])) {
form_error($element, t('%name field is not in the right format.', array('%name' => $element['#title'])));
}
}
}
/**
* Processes a container element.
*

View File

@ -361,7 +361,7 @@ function system_element_info() {
'#size' => 60,
'#maxlength' => 128,
'#autocomplete_path' => FALSE,
'#process' => array('form_process_autocomplete', 'ajax_process_form'),
'#process' => array('form_process_autocomplete', 'ajax_process_form', 'form_process_pattern'),
'#theme' => 'textfield',
'#theme_wrappers' => array('form_element'),
);
@ -370,7 +370,7 @@ function system_element_info() {
'#size' => 30,
'#maxlength' => 128,
'#autocomplete_path' => FALSE,
'#process' => array('form_process_autocomplete', 'ajax_process_form'),
'#process' => array('form_process_autocomplete', 'ajax_process_form', 'form_process_pattern'),
'#theme' => 'tel',
'#theme_wrappers' => array('form_element'),
);
@ -379,7 +379,7 @@ function system_element_info() {
'#size' => 60,
'#maxlength' => EMAIL_MAX_LENGTH,
'#autocomplete_path' => FALSE,
'#process' => array('form_process_autocomplete', 'ajax_process_form'),
'#process' => array('form_process_autocomplete', 'ajax_process_form', 'form_process_pattern'),
'#element_validate' => array('form_validate_email'),
'#theme' => 'email',
'#theme_wrappers' => array('form_element'),
@ -389,7 +389,7 @@ function system_element_info() {
'#size' => 60,
'#maxlength' => 255,
'#autocomplete_path' => FALSE,
'#process' => array('form_process_autocomplete', 'ajax_process_form'),
'#process' => array('form_process_autocomplete', 'ajax_process_form', 'form_process_pattern'),
'#element_validate' => array('form_validate_url'),
'#theme' => 'url',
'#theme_wrappers' => array('form_element'),
@ -437,7 +437,7 @@ function system_element_info() {
'#input' => TRUE,
'#size' => 60,
'#maxlength' => 128,
'#process' => array('ajax_process_form'),
'#process' => array('ajax_process_form', 'form_process_pattern'),
'#theme' => 'password',
'#theme_wrappers' => array('form_element'),
);

View File

@ -784,6 +784,65 @@ class FormValidationTestCase extends DrupalWebTestCase {
$this->assertText(t('!name field is required.', array('!name' => 'Title')));
$this->assertText('Test element is invalid');
}
/**
* Tests #pattern validation.
*/
function testPatternValidation() {
$textfield_error = t('%name field is not in the right format.', array('%name' => 'One digit followed by lowercase letters'));
$tel_error = t('%name field is not in the right format.', array('%name' => 'Everything except numbers'));
$password_error = t('%name field is not in the right format.', array('%name' => 'Password'));
// Invalid textfield, valid tel.
$edit = array(
'textfield' => 'invalid',
'tel' => 'valid',
);
$this->drupalPost('form-test/pattern', $edit, 'Submit');
$this->assertRaw($textfield_error);
$this->assertNoRaw($tel_error);
$this->assertNoRaw($password_error);
// Valid textfield, invalid tel, valid password.
$edit = array(
'textfield' => '7seven',
'tel' => '818937',
'password' => '0100110',
);
$this->drupalPost('form-test/pattern', $edit, 'Submit');
$this->assertNoRaw($textfield_error);
$this->assertRaw($tel_error);
$this->assertNoRaw($password_error);
// Non required fields are not validated if empty.
$edit = array(
'textfield' => '',
'tel' => '',
);
$this->drupalPost('form-test/pattern', $edit, 'Submit');
$this->assertNoRaw($textfield_error);
$this->assertNoRaw($tel_error);
$this->assertNoRaw($password_error);
// Invalid password.
$edit = array(
'password' => $this->randomName(),
);
$this->drupalPost('form-test/pattern', $edit, 'Submit');
$this->assertNoRaw($textfield_error);
$this->assertNoRaw($tel_error);
$this->assertRaw($password_error);
// The pattern attribute overrides #pattern and is not validated on the
// server side.
$edit = array(
'textfield' => '',
'tel' => '',
'url' => 'http://www.example.com/',
);
$this->drupalPost('form-test/pattern', $edit, 'Submit');
$this->assertNoRaw(t('%name field is not in the right format.', array('%name' => 'Client side validation')));
}
}
/**

View File

@ -37,6 +37,12 @@ function form_test_menu() {
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
$items['form-test/pattern'] = array(
'title' => 'Pattern validation',
'page callback' => 'drupal_get_form',
'page arguments' => array('form_test_pattern_form'),
'access callback' => TRUE,
);
$items['form_test/tableselect/multiple-true'] = array(
'title' => 'Tableselect checkboxes test',
@ -531,6 +537,41 @@ function form_test_limit_validation_errors_form_partial_submit($form, $form_stat
}
}
/**
* Builds a simple form using the FAPI #pattern proterty.
*/
function form_test_pattern_form($form, &$form_state) {
$form['textfield'] = array(
'#type' => 'textfield',
'#title' => 'One digit followed by lowercase letters',
'#pattern' => '[0-9][a-z]+',
);
$form['tel'] = array(
'#type' => 'tel',
'#title' => 'Everything except numbers',
'#pattern' => '[^\d]*',
);
$form['password'] = array(
'#type' => 'password',
'#title' => 'Password',
'#pattern' => '[01]+',
);
$form['url'] = array(
'#type' => 'url',
'#title' => 'Client side validation',
'#decription' => 'Just client side validation, using the #pattern attribute.',
'#attributes' => array(
'pattern' => '.*foo.*',
),
'#pattern' => 'ignored',
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Submit',
);
return $form;
}
/**
* Create a header and options array. Helper function for callbacks.
*/