diff --git a/core/includes/common.inc b/core/includes/common.inc
index 4229d52..7d16edc 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -6719,6 +6719,9 @@ function drupal_common_theme() {
'textfield' => array(
'render element' => 'element',
),
+ 'url' => array(
+ 'render element' => 'element',
+ ),
'form' => array(
'render element' => 'element',
),
diff --git a/core/includes/form.inc b/core/includes/form.inc
index a12fb34..3ee73fc 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -3694,8 +3694,59 @@ function theme_textfield($variables) {
element_set_attributes($element, array('id', 'name', 'value', 'size', 'maxlength', 'placeholder'));
_form_set_class($element, array('form-text'));
+ $extra = form_add_autocomplete($element);
+ $output = '';
+
+ return $output . $extra;
+}
+
+/**
+ * Returns HTML for an 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_set_attributes($element, array('type', 'id', 'name', 'value', 'size', 'maxlength', 'placeholder'));
+ _form_set_class($element, array('form-text', 'form-url'));
+
+ $extra = form_add_autocomplete($element);
+ $output = '';
+
+ 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) {
+ if ($element['#value'] && !valid_url($element['#value'], TRUE)) {
+ form_error($element, t('The URL %url is not valid.', array('%url' => $element['#value'])));
+ }
+}
+
+/**
+ * Return the autocompletion HTML for a form element.
+ *
+ * @param $element
+ * The renderable element to process for autocompletion.
+ *
+ * @return
+ * The rendered autocompletion element HTML, or an empty string if the field
+ * has no autocompletion enabled.
+ */
+function form_add_autocomplete(&$element) {
$extra = '';
- if ($element['#autocomplete_path'] && drupal_valid_path($element['#autocomplete_path'])) {
+
+ if (!empty($element['#autocomplete_path']) && drupal_valid_path($element['#autocomplete_path'])) {
drupal_add_library('system', 'drupal.autocomplete');
$element['#attributes']['class'][] = 'form-autocomplete';
@@ -3708,9 +3759,7 @@ function theme_textfield($variables) {
$extra = '';
}
- $output = '';
-
- return $output . $extra;
+ return $extra;
}
/**
diff --git a/core/modules/aggregator/aggregator.admin.inc b/core/modules/aggregator/aggregator.admin.inc
index 08087af..914cb97 100644
--- a/core/modules/aggregator/aggregator.admin.inc
+++ b/core/modules/aggregator/aggregator.admin.inc
@@ -70,7 +70,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' => 255,
@@ -133,10 +134,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']));
@@ -241,7 +238,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.'),
@@ -287,11 +284,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 either 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.'));
- }
}
/**
diff --git a/core/modules/aggregator/aggregator.test b/core/modules/aggregator/aggregator.test
index 381fb95..1ce78d2 100644
--- a/core/modules/aggregator/aggregator.test
+++ b/core/modules/aggregator/aggregator.test
@@ -660,7 +660,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.'), t('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.'));
@@ -887,4 +887,3 @@ class FeedParserTestCase extends AggregatorTestCase {
$this->assertEqual('urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a', db_query('SELECT guid FROM {aggregator_item} WHERE link = :link', array(':link' => 'http://example.org/2003/12/13/atom03'))->fetchField(), 'Atom entry id element is parsed correctly.');
}
}
-
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index ae9278c..e752492 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1958,7 +1958,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,
@@ -2134,9 +2134,6 @@ function comment_form_validate($form, &$form_state) {
if ($form_state['values']['mail'] && !valid_email_address($form_state['values']['mail'])) {
form_set_error('mail', t('The e-mail address you specified is not valid.'));
}
- 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 http://example.com/directory.'));
- }
}
/**
diff --git a/core/modules/simpletest/drupal_web_test_case.php b/core/modules/simpletest/drupal_web_test_case.php
index 9d993d4..48fce64 100644
--- a/core/modules/simpletest/drupal_web_test_case.php
+++ b/core/modules/simpletest/drupal_web_test_case.php
@@ -2160,6 +2160,7 @@ class DrupalWebTestCase extends DrupalTestCase {
case 'textarea':
case 'hidden':
case 'password':
+ case 'url':
$post[$name] = $edit[$name];
unset($edit[$name]);
break;
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index f4261e1..f8706c2 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -361,6 +361,16 @@ function system_element_info() {
'#theme' => 'textfield',
'#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,
diff --git a/core/modules/update/update.manager.inc b/core/modules/update/update.manager.inc
index 59858eb..dc4292d 100644
--- a/core/modules/update/update.manager.inc
+++ b/core/modules/update/update.manager.inc
@@ -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.'));
- }
- }
}
/**