Commit da3a59b5 authored by catch's avatar catch

Issue #1174630 by Dave Reid, Niklas Fiekas, ericduran, xjm: Added new HTML5 FAPI element: url.

parent b9e92441
......@@ -6952,6 +6952,9 @@ function drupal_common_theme() {
'email' => array(
'render element' => 'element',
),
'url' => array(
'render element' => 'element',
),
'form' => array(
'render element' => 'element',
),
......
......@@ -3836,6 +3836,56 @@ function theme_tel($variables) {
return $output . $extra;
}
/**
* Returns HTML for a url form element.
*
* @param $variables
* An associative array containing:
* - element: An associative array containing the properties of the element.
* Properties used: #title, #value, #description, #size, #maxlength,
* #placeholder, #required, #attributes, #autocomplete_path.
*
* @ingroup themeable
*/
function theme_url($variables) {
$element = $variables['element'];
$element['#attributes']['type'] = 'url';
element_set_attributes($element, array('id', 'name', 'value', 'size', 'maxlength', 'placeholder'));
_form_set_class($element, array('form-url'));
$extra = '';
if ($element['#autocomplete_path'] && drupal_valid_path($element['#autocomplete_path'])) {
drupal_add_library('system', 'drupal.autocomplete');
$element['#attributes']['class'][] = 'form-autocomplete';
$attributes = array();
$attributes['type'] = 'hidden';
$attributes['id'] = $element['#attributes']['id'] . '-autocomplete';
$attributes['value'] = url($element['#autocomplete_path'], array('absolute' => TRUE));
$attributes['disabled'] = 'disabled';
$attributes['class'][] = 'autocomplete';
$extra = '<input' . drupal_attributes($attributes) . ' />';
}
$output = '<input' . drupal_attributes($element['#attributes']) . ' />';
return $output . $extra;
}
/**
* Form element validation handler for #type 'url'.
*
* Note that #maxlength and #required is validated by _form_validate() already.
*/
function form_validate_url(&$element, &$form_state) {
$value = trim($element['#value']);
form_set_value($element, $value, $form_state);
if ($value !== '' && !valid_url($value, TRUE)) {
form_error($element, t('The URL %url is not valid.', array('%url' => $value)));
}
}
/**
* Returns HTML for a form.
*
......
......@@ -77,7 +77,8 @@ function aggregator_form_feed($form, &$form_state, stdClass $feed = NULL) {
'#description' => t('The name of the feed (or the name of the website providing the feed).'),
'#required' => TRUE,
);
$form['url'] = array('#type' => 'textfield',
$form['url'] = array(
'#type' => 'url',
'#title' => t('URL'),
'#default_value' => isset($feed->url) ? $feed->url : '',
'#maxlength' => NULL,
......@@ -142,10 +143,6 @@ function aggregator_form_feed($form, &$form_state, stdClass $feed = NULL) {
*/
function aggregator_form_feed_validate($form, &$form_state) {
if ($form_state['values']['op'] == t('Save')) {
// Ensure URL is valid.
if (!valid_url($form_state['values']['url'], TRUE)) {
form_set_error('url', t('The URL %url is invalid. Enter a fully-qualified URL, such as http://www.example.com/feed.xml.', array('%url' => $form_state['values']['url'])));
}
// Check for duplicate titles.
if (isset($form_state['values']['fid'])) {
$result = db_query("SELECT title, url FROM {aggregator_feed} WHERE (title = :title OR url = :url) AND fid <> :fid", array(':title' => $form_state['values']['title'], ':url' => $form_state['values']['url'], ':fid' => $form_state['values']['fid']));
......@@ -260,7 +257,7 @@ function aggregator_form_opml($form, &$form_state) {
'#description' => t('Upload an OPML file containing a list of feeds to be imported.'),
);
$form['remote'] = array(
'#type' => 'textfield',
'#type' => 'url',
'#title' => t('OPML Remote URL'),
'#maxlength' => 1024,
'#description' => t('Enter the URL of an OPML file. This file will be downloaded and processed only once on submission of the form.'),
......@@ -308,11 +305,6 @@ function aggregator_form_opml_validate($form, &$form_state) {
if (empty($form_state['values']['remote']) == empty($_FILES['files']['name']['upload'])) {
form_set_error('remote', t('You must <em>either</em> upload a file or enter a URL.'));
}
// Validate the URL, if one was entered.
if (!empty($form_state['values']['remote']) && !valid_url($form_state['values']['remote'], TRUE)) {
form_set_error('remote', t('This URL is not valid.'));
}
}
/**
......
......@@ -704,7 +704,7 @@ class ImportOPMLTestCase extends AggregatorTestCase {
$edit = array('remote' => 'invalidUrl://empty');
$this->drupalPost('admin/config/services/aggregator/add/opml', $edit, t('Import'));
$this->assertText(t('This URL is not valid.'), t('Error if the URL is invalid.'));
$this->assertText(t('The URL invalidUrl://empty is not valid.'), 'Error if the URL is invalid.');
$after = db_query('SELECT COUNT(*) FROM {aggregator_feed}')->fetchField();
$this->assertEqual($before, $after, t('No feeds were added during the three last form submissions.'));
......
......@@ -1791,7 +1791,7 @@ function comment_form($form, &$form_state, $comment) {
'#access' => $is_admin || (!$user->uid && $anonymous_contact != COMMENT_ANONYMOUS_MAYNOT_CONTACT),
);
$form['author']['homepage'] = array(
'#type' => 'textfield',
'#type' => 'url',
'#title' => t('Homepage'),
'#default_value' => $comment->homepage,
'#maxlength' => 255,
......@@ -1982,9 +1982,6 @@ function comment_form_validate($form, &$form_state) {
}
}
}
if ($form_state['values']['homepage'] && !valid_url($form_state['values']['homepage'], TRUE)) {
form_set_error('homepage', t('The URL of your homepage is not valid. Remember that it must be fully qualified, i.e. of the form <code>http://example.com/directory</code>.'));
}
}
/**
......
......@@ -2262,6 +2262,7 @@ protected function handleForm(&$post, &$edit, &$upload, $submit, $form) {
case 'text':
case 'tel':
case 'textarea':
case 'url':
case 'hidden':
case 'password':
case 'email':
......
......@@ -40,6 +40,9 @@ class FormsTestCase extends DrupalWebTestCase {
$elements['telephone']['element'] = array('#title' => $this->randomName(), '#type' => 'tel');
$elements['telephone']['empty_values'] = $empty_strings;
$elements['url']['element'] = array('#title' => $this->randomName(), '#type' => 'url');
$elements['url']['empty_values'] = $empty_strings;
$elements['password']['element'] = array('#title' => $this->randomName(), '#type' => 'password');
$elements['password']['empty_values'] = $empty_strings;
......@@ -261,7 +264,7 @@ class FormsTestCase extends DrupalWebTestCase {
// All the elements should be marked as disabled, including the ones below
// the disabled container.
$this->assertEqual(count($disabled_elements), 35, 'The correct elements have the disabled property in the HTML code.');
$this->assertEqual(count($disabled_elements), 36, 'The correct elements have the disabled property in the HTML code.');
$this->drupalPost(NULL, $edit, t('Submit'));
$returned_values['hijacked'] = drupal_json_decode($this->content);
......@@ -396,7 +399,7 @@ class FormElementTestCase extends DrupalWebTestCase {
$this->drupalGet('form-test/placeholder-text');
$expected = 'placeholder-text';
// Test to make sure non-textarea elements have the proper placeholder text.
foreach (array('textfield', 'tel', 'password', 'email') as $type) {
foreach (array('textfield', 'tel', 'url', 'password', 'email') as $type) {
$element = $this->xpath('//input[@id=:id and @placeholder=:expected]', array(
':id' => 'edit-' . $type,
':expected' => $expected,
......@@ -1671,3 +1674,48 @@ class FormEmailTestCase extends DrupalWebTestCase {
$this->assertEqual($values['email_required'], 'example@drupal.org');
}
}
/**
* Tests url element.
*/
class FormUrlTestCase extends DrupalWebTestCase {
protected $profile = 'testing';
public static function getInfo() {
return array(
'name' => 'Form API url',
'description' => 'Tests the form API url element.',
'group' => 'Form API',
);
}
public function setUp() {
parent::setUp('form_test');
}
/**
* Tests that #type 'url' fields are properly validated and trimmed.
*/
function testFormUrl() {
$edit = array();
$edit['url'] = 'http://';
$edit['url_required'] = ' ';
$this->drupalPost('form-test/url', $edit, 'Submit');
$this->assertRaw(t('The URL %url is not valid.', array('%url' => 'http://')));
$this->assertRaw(t('!name field is required.', array('!name' => 'Required URL')));
$edit = array();
$edit['url'] = "\n";
$edit['url_required'] = 'http://example.com/ ';
$values = drupal_json_decode($this->drupalPost('form-test/url', $edit, 'Submit'));
$this->assertIdentical($values['url'], '');
$this->assertEqual($values['url_required'], 'http://example.com/');
$edit = array();
$edit['url'] = 'http://foo.bar.example.com/';
$edit['url_required'] = 'http://drupal.org/node/1174630?page=0&foo=bar#new';
$values = drupal_json_decode($this->drupalPost('form-test/url', $edit, 'Submit'));
$this->assertEqual($values['url'], $edit['url']);
$this->assertEqual($values['url_required'], $edit['url_required']);
}
}
......@@ -131,6 +131,12 @@ function form_test_menu() {
'page arguments' => array('form_test_email'),
'access callback' => TRUE,
);
$items['form-test/url'] = array(
'title' => t('URL'),
'page callback' => 'drupal_get_form',
'page arguments' => array('form_test_url'),
'access callback' => TRUE,
);
$items['form-test/disabled-elements'] = array(
'title' => t('Form test'),
......@@ -1033,7 +1039,7 @@ function form_test_select_submit($form, &$form_state) {
* Builds a form to test the placeholder attribute.
*/
function form_test_placeholder_test($form, &$form_state) {
foreach (array('textfield', 'textarea', 'password', 'tel', 'email') as $type) {
foreach (array('textfield', 'textarea', 'url', 'password', 'tel', 'email') as $type) {
$form[$type] = array(
'#type' => $type,
'#title' => $type,
......@@ -1136,6 +1142,39 @@ function form_test_email_submit($form, &$form_state) {
exit();
}
/**
* Form constructor for testing #type 'url' elements.
*
* @see form_test_url_submit()
* @ingroup forms
*/
function form_test_url($form, &$form_state) {
$form['url'] = array(
'#type' => 'url',
'#title' => 'Optional URL',
'#description' => 'An optional URL field.',
);
$form['url_required'] = array(
'#type' => 'url',
'#title' => 'Required URL',
'#description' => 'A required URL field.',
'#required' => TRUE,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Submit',
);
return $form;
}
/**
* Form submission handler for form_test_url().
*/
function form_test_url_submit($form, &$form_state) {
drupal_json_output($form_state['values']);
exit();
}
/**
* Build a form to test disabled elements.
*/
......@@ -1235,7 +1274,7 @@ function _form_test_disabled_elements($form, &$form_state) {
$form['disabled_container'] = array(
'#disabled' => TRUE,
);
foreach (array('textfield', 'textarea', 'hidden', 'tel') as $type) {
foreach (array('textfield', 'textarea', 'hidden', 'tel', 'url') as $type) {
$form['disabled_container']['disabled_container_' . $type] = array(
'#type' => $type,
'#title' => $type,
......@@ -1252,6 +1291,14 @@ function _form_test_disabled_elements($form, &$form_state) {
'#test_hijack_value' => 'bar@example.com',
);
// Try to hijack the URL field with a valid URL.
$form['disabled_container']['disabled_container_url'] = array(
'#type' => 'url',
'#title' => 'url',
'#default_value' => 'http://example.com',
'#test_hijack_value' => 'http://example.com/foo',
);
// Text format.
$form['text_format'] = array(
'#type' => 'text_format',
......
......@@ -384,6 +384,16 @@ function system_element_info() {
'#theme' => 'email',
'#theme_wrappers' => array('form_element'),
);
$types['url'] = array(
'#input' => TRUE,
'#size' => 60,
'#maxlength' => 255,
'#autocomplete_path' => FALSE,
'#process' => array('ajax_process_form'),
'#element_validate' => array('form_validate_url'),
'#theme' => 'url',
'#theme_wrappers' => array('form_element'),
);
$types['machine_name'] = array(
'#input' => TRUE,
'#default_value' => NULL,
......
......@@ -492,7 +492,7 @@ function update_manager_install_form($form, &$form_state, $context) {
);
$form['project_url'] = array(
'#type' => 'textfield',
'#type' => 'url',
'#title' => t('Install from a URL'),
'#description' => t('For example: %url', array('%url' => 'http://ftp.drupal.org/files/projects/name.tar.gz')),
);
......@@ -592,12 +592,6 @@ function update_manager_install_form_validate($form, &$form_state) {
if (!($form_state['values']['project_url'] XOR !empty($_FILES['files']['name']['project_upload']))) {
form_set_error('project_url', t('You must either provide a URL or upload an archive file to install.'));
}
if ($form_state['values']['project_url']) {
if (!valid_url($form_state['values']['project_url'], TRUE)) {
form_set_error('project_url', t('The provided URL is invalid.'));
}
}
}
/**
......
......@@ -1191,6 +1191,7 @@ select.form-select {
input.form-text,
input.form-tel,
input.form-email,
input.form-url,
textarea.form-textarea,
select.form-select {
border: 1px solid #ccc;
......
......@@ -603,6 +603,7 @@ div.teaser-checkbox .form-item,
.form-disabled input.form-text,
.form-disabled input.form-tel,
.form-disabled input.form-email,
.form-disabled input.form-url,
.form-disabled input.form-file,
.form-disabled textarea.form-textarea,
.form-disabled select.form-select {
......@@ -691,6 +692,7 @@ input.form-autocomplete,
input.form-text,
input.form-tel,
input.form-email,
input.form-url,
input.form-file,
textarea.form-textarea,
select.form-select {
......@@ -706,6 +708,7 @@ select.form-select {
input.form-text:focus,
input.form-tel:focus,
input.form-email:focus,
input.form-url:focus,
input.form-file:focus,
textarea.form-textarea:focus,
select.form-select:focus {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment