diff options
author | Dries Buytaert <dries@buytaert.net> | 2010-10-13 13:43:21 +0000 |
---|---|---|
committer | Dries Buytaert <dries@buytaert.net> | 2010-10-13 13:43:21 +0000 |
commit | 284f2b11a48b893cbd13d5429ad68d207488e4e6 (patch) | |
tree | 84b9bd1672ec7d9f585c2e4019d2f1f3b508afe1 /modules | |
parent | 3e6b9b5ea35dfb32e3c30a4d012f67c1d268a570 (diff) | |
download | brdo-284f2b11a48b893cbd13d5429ad68d207488e4e6.tar.gz brdo-284f2b11a48b893cbd13d5429ad68d207488e4e6.tar.bz2 |
- Patch #902644 by sun, tobiasb: machine names are too hard to implement. Date types and menu names are not validated.
This patch fixes a bug, but is also a last minute clean-up that will help with better distribution support. We discussed this in http://drupal.org/node/933846.
Diffstat (limited to 'modules')
-rw-r--r-- | modules/menu/menu.admin.inc | 114 | ||||
-rw-r--r-- | modules/menu/menu.test | 12 | ||||
-rw-r--r-- | modules/node/content_types.inc | 51 | ||||
-rw-r--r-- | modules/system/system.admin.css | 10 | ||||
-rw-r--r-- | modules/system/system.admin.inc | 24 | ||||
-rw-r--r-- | modules/system/system.js | 74 | ||||
-rw-r--r-- | modules/system/system.module | 12 | ||||
-rw-r--r-- | modules/system/system.test | 2 | ||||
-rw-r--r-- | modules/taxonomy/taxonomy.admin.inc | 53 | ||||
-rw-r--r-- | modules/taxonomy/taxonomy.test | 2 |
10 files changed, 101 insertions, 253 deletions
diff --git a/modules/menu/menu.admin.inc b/modules/menu/menu.admin.inc index 622df38ab..e4dc02951 100644 --- a/modules/menu/menu.admin.inc +++ b/modules/menu/menu.admin.inc @@ -419,57 +419,45 @@ function menu_edit_item_submit($form, &$form_state) { */ function menu_edit_menu($form, &$form_state, $type, $menu = array()) { $system_menus = menu_list_system_menus(); - $menu += array('menu_name' => '', 'old_name' => '', 'title' => '', 'description' => ''); - if (!empty($menu['menu_name'])) { - $menu['old_name'] = $menu['menu_name']; - } - $form['old_name'] = array('#type' => 'value', '#value' => $menu['old_name']); + $menu += array( + 'menu_name' => '', + 'old_name' => !empty($menu['menu_name']) ? $menu['menu_name'] : '', + 'title' => '', + 'description' => '', + ); + // Allow menu_edit_menu_submit() and other form submit handlers to determine + // whether the menu already exists. + $form['#insert'] = empty($menu['old_name']); + $form['old_name'] = array( + '#type' => 'value', + '#value' => $menu['old_name'], + ); - // The title of a system menu cannot be altered. - if (isset($system_menus[$menu['menu_name']])) { - $form['title'] = array('#type' => 'value', '#value' => $menu['title']); - } - else { - $form['title'] = array( - '#type' => 'textfield', - '#title' => t('Title'), - '#default_value' => $menu['title'], - '#required' => TRUE, - '#field_suffix' => ' <small id="edit-title-suffix"> </small>', - ); - } + $form['title'] = array( + '#type' => 'textfield', + '#title' => t('Title'), + '#default_value' => $menu['title'], + '#required' => TRUE, + // The title of a system menu cannot be altered. + '#access' => !isset($system_menus[$menu['menu_name']]), + ); - // The internal menu name can only be defined during initial menu creation. - if (!empty($menu['old_name'])) { - $form['#insert'] = FALSE; - $form['menu_name'] = array('#type' => 'value', '#value' => $menu['menu_name']); - } - else { - $form['#insert'] = TRUE; - $js_settings = array( - 'type' => 'setting', - 'data' => array( - 'machineReadableValue' => array( - 'title' => array( - 'text' => t('URL path'), - 'target' => 'menu-name', - 'searchPattern' => '[^a-z0-9]+', - 'replaceToken' => '-', - ), - ), - ), - ); - $form['menu_name'] = array( - '#type' => 'textfield', - '#title' => t('Menu name'), - '#maxsize' => MENU_MAX_MENU_NAME_LENGTH_UI, - '#description' => t('This text will be used to construct the URL for the menu. The name must contain only lowercase letters, numbers and hyphens, and must be unique.'), - '#required' => TRUE, - '#attached' => array( - 'js' => array(drupal_get_path('module', 'system') . '/system.js', $js_settings), - ), - ); - } + $form['menu_name'] = array( + '#type' => 'machine_name', + '#title' => t('Menu name'), + '#default_value' => $menu['menu_name'], + '#maxlength' => MENU_MAX_MENU_NAME_LENGTH_UI, + '#description' => t('A unique name to construct the URL for the menu. It must only contain lowercase letters, numbers and hyphens.'), + '#machine_name' => array( + 'exists' => 'menu_edit_menu_name_exists', + 'source' => array('title'), + 'label' => t('URL path'), + 'replace_pattern' => '[^a-z0-9-]+', + 'replace' => '-', + ), + // A menu's machine name cannot be changed. + '#disabled' => !empty($menu['old_name']) || isset($system_menus[$menu['menu_name']]), + ); $form['description'] = array( '#type' => 'textarea', @@ -560,26 +548,18 @@ function menu_delete_menu_confirm_submit($form, &$form_state) { } /** - * Validates the human and machine-readable names when adding or editing a menu. + * Returns whether a menu name already exists. + * + * @see menu_edit_menu() + * @see form_validate_machine_name() */ -function menu_edit_menu_validate($form, &$form_state) { - $item = $form_state['values']; - if (preg_match('/[^a-z0-9-]/', $item['menu_name'])) { - form_set_error('menu_name', t('The menu name may only consist of lowercase letters, numbers, and hyphens.')); - } - if ($form['#insert']) { - if (strlen($item['menu_name']) > MENU_MAX_MENU_NAME_LENGTH_UI) { - form_set_error('menu_name', format_plural(MENU_MAX_MENU_NAME_LENGTH_UI, "The menu name can't be longer than 1 character.", "The menu name can't be longer than @count characters.")); - } +function menu_edit_menu_name_exists($value) { + // 'menu-' is added to the menu name to avoid name-space conflicts. + $value = 'menu-' . $value; + $custom_exists = db_query_range('SELECT 1 FROM {menu_custom} WHERE menu_name = :menu', 0, 1, array(':menu' => $value))->fetchField(); + $link_exists = db_query_range("SELECT 1 FROM {menu_links} WHERE menu_name = :menu", 0, 1, array(':menu' => $value))->fetchField(); - // We will add 'menu-' to the menu name to help avoid name-space conflicts. - $item['menu_name'] = 'menu-' . $item['menu_name']; - $custom_exists = db_query_range('SELECT 1 FROM {menu_custom} WHERE menu_name = :menu', 0, 1, array(':menu' => $item['menu_name']))->fetchField(); - $link_exists = db_query_range("SELECT 1 FROM {menu_links} WHERE menu_name = :menu", 0, 1, array(':menu' => $item['menu_name']))->fetchField(); - if ($custom_exists || $link_exists) { - form_set_error('menu_name', t('The menu already exists.')); - } - } + return $custom_exists || $link_exists; } /** diff --git a/modules/menu/menu.test b/modules/menu/menu.test index 2c5900181..a90fbfb28 100644 --- a/modules/menu/menu.test +++ b/modules/menu/menu.test @@ -140,7 +140,11 @@ class MenuTestCase extends DrupalWebTestCase { $this->drupalPost('admin/structure/menu/add', $edit, t('Save')); // Verify that using a menu_name that is too long results in a validation message. - $this->assertText(format_plural(MENU_MAX_MENU_NAME_LENGTH_UI, "The menu name can't be longer than 1 character.", "The menu name can't be longer than @count characters."), t('Validation failed when menu name is too long.')); + $this->assertRaw(t('!name cannot be longer than %max characters but is currently %length characters long.', array( + '!name' => t('Menu name'), + '%max' => MENU_MAX_MENU_NAME_LENGTH_UI, + '%length' => drupal_strlen($menu_name), + ))); // Change the menu_name so it no longer exceeds the maximum length. $menu_name = substr(hash('sha256', $this->randomName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI); @@ -148,7 +152,11 @@ class MenuTestCase extends DrupalWebTestCase { $this->drupalPost('admin/structure/menu/add', $edit, t('Save')); // Verify that no validation error is given for menu_name length. - $this->assertNoText(format_plural(MENU_MAX_MENU_NAME_LENGTH_UI, "The menu name can't be longer than 1 character.", "The menu name can't be longer than @count characters."), t('Validation failed when menu name is too long.')); + $this->assertNoRaw(t('!name cannot be longer than %max characters but is currently %length characters long.', array( + '!name' => t('Menu name'), + '%max' => MENU_MAX_MENU_NAME_LENGTH_UI, + '%length' => drupal_strlen($menu_name), + ))); // Unlike most other modules, there is no confirmation message displayed. $this->drupalGet('admin/structure/menu'); diff --git a/modules/node/content_types.inc b/modules/node/content_types.inc index 23565ce24..d31becb0d 100644 --- a/modules/node/content_types.inc +++ b/modules/node/content_types.inc @@ -94,41 +94,20 @@ function node_type_form($form, &$form_state, $type = NULL) { '#description' => t('The human-readable name of this content type. This text will be displayed as part of the list on the <em>Add new content</em> page. It is recommended that this name begin with a capital letter and contain only letters, numbers, and spaces. This name must be unique.'), '#required' => TRUE, '#size' => 30, - '#field_suffix' => ' <small id="edit-name-suffix">' . ($type->locked ? t('Machine name: @name', array('@name' => $type->type)) : ' ') . '</small>', ); - if (!$type->locked) { - $js_settings = array( - 'type' => 'setting', - 'data' => array( - 'machineReadableValue' => array( - 'name' => array( - 'text' => t('Machine name'), - 'target' => 'type', - 'searchPattern' => '[^a-z0-9]+', - 'replaceToken' => '_', - ), - ), - ), - ); - $form['type'] = array( - '#title' => t('Machine name'), - '#type' => 'textfield', - '#default_value' => $type->type, - '#maxlength' => 32, - '#required' => TRUE, - '#description' => t('The machine-readable name of this content type. This text will be used for constructing the URL of the <em>add new content</em> page for this content type. This name must contain only lowercase letters, numbers, and underscores. Underscores will be converted into hyphens when constructing the URL of the <em>add new content</em> page. This name must be unique.'), - '#attached' => array( - 'js' => array(drupal_get_path('module', 'system') . '/system.js', $js_settings), - ), - ); - } - else { - $form['type'] = array( - '#type' => 'value', - '#value' => $type->type, - ); - } + $form['type'] = array( + '#type' => 'machine_name', + '#default_value' => $type->type, + '#maxlength' => 32, + '#disabled' => $type->locked, + '#machine_name' => array( + 'exists' => 'node_type_load', + ), + '#description' => t('A unique machine-readable name for this content type. It must only contain lowercase letters, numbers, and underscores. This name will be used for constructing the URL of the %node-add page, in which underscores will be converted into hyphens.', array( + '%node-add' => t('Add new content'), + )), + ); $form['description'] = array( '#title' => t('Description'), @@ -276,12 +255,6 @@ function node_type_form_validate($form, &$form_state) { $types = node_type_get_names(); if (!$form_state['values']['locked']) { - if (isset($types[$type->type]) && $type->type != $old_type) { - form_set_error('type', t('The machine-readable name %type is already taken.', array('%type' => $type->type))); - } - if (!preg_match('!^[a-z0-9_]+$!', $type->type)) { - form_set_error('type', t('The machine-readable name must contain only lowercase letters, numbers, and underscores.')); - } // 'theme' conflicts with theme_node_form(). // '0' is invalid, since elsewhere we check it using empty(). if (in_array($type->type, array('0', 'theme'))) { diff --git a/modules/system/system.admin.css b/modules/system/system.admin.css index 1d3882669..adcc369fd 100644 --- a/modules/system/system.admin.css +++ b/modules/system/system.admin.css @@ -46,6 +46,16 @@ div.admin .expert-link { } /** + * Quick inline admin links. + */ +small .admin-link:before { + content: '['; +} +small .admin-link:after { + content: ']'; +} + +/** * Modules page. */ #system-modules div.incompatible { diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc index b2f5ee240..431a41242 100644 --- a/modules/system/system.admin.inc +++ b/modules/system/system.admin.inc @@ -2068,28 +2068,12 @@ function system_add_date_format_type_form($form, &$form_state) { '#title' => t('Date type'), '#type' => 'textfield', '#required' => TRUE, - '#field_suffix' => ' <small id="edit-date-type-suffix"> </small>', - ); - $js_settings = array( - 'type' => 'setting', - 'data' => array( - 'machineReadableValue' => array( - 'date-type' => array( - 'text' => t('Machine name'), - 'target' => 'machine-name', - 'searchPattern' => '[^a-z0-9]+', - 'replaceToken' => '_', - ), - ), - ), ); $form['machine_name'] = array( - '#title' => t('Machine readable name'), - '#description' => t('The unique machine readable name for this date type, can only contain lowercase letters, numbers and underscores.'), - '#type' => 'textfield', - '#required' => TRUE, - '#attached' => array( - 'js' => array(drupal_get_path('module', 'system') . '/system.js', $js_settings), + '#type' => 'machine_name', + '#machine_name' => array( + 'exists' => 'system_get_date_types', + 'source' => array('date_type'), ), ); diff --git a/modules/system/system.js b/modules/system/system.js index 07c2eb64f..3cee79f30 100644 --- a/modules/system/system.js +++ b/modules/system/system.js @@ -148,78 +148,4 @@ Drupal.behaviors.pageCache = { } }; -/** - * Attach the auto machine readable name behavior. - * - * Settings are expected to be an object of elements to process, where the key - * defines the source element in the form and the value is an object defining - * the following properties: - * - text: The label to display before the auto-generated value. - * - target: The target form element name. - * - searchPattern: A regular expression (without modifiers) matching disallowed - * characters in the machine readable name, f.e. '[^a-z0-9]+'. - * - replaceToken: A replacement string to replace disallowed characters, f.e. - * '-' or '_'. - * - * @see menu_edit_menu() - */ -Drupal.behaviors.machineReadableValue = { - attach: function () { - var self = this; - - for (var value in Drupal.settings.machineReadableValue) { - var settings = Drupal.settings.machineReadableValue[value]; - - // Build selector for the source name entered by a user. - var source = '#edit-' + value; - var suffix = source + '-suffix'; - // Build selector for the machine readable name. - var target = '#edit-' + settings.target; - // Build selector for the wrapper element around the target field. - var wrapper = '.form-item-' + settings.target; - - // Do not process the element if we got an error or the given name and the - // machine readable name are identical or the machine readable name is - // empty. - if (!$(target).hasClass('error') && ($(target).val() == '' || $(target).val() == self.transliterate($(source).val(), settings))) { - // Hide wrapper element. - $(wrapper).hide(); - // Bind keyup event to source element. - $(source).keyup(function () { - var machine = self.transliterate($(this).val(), settings); - if (machine != '_' && machine != '') { - // Set machine readable name to the user entered value. - $(target).val(machine); - // Append the machine readable name and a link to edit it to the source field. - $(suffix).empty().append(' ' + settings.text + ': ' + machine + ' [').append($('<a href="#">' + Drupal.t('Edit') + '</a>').click(function () { - $(wrapper).show(); - $(target).focus(); - $(suffix).hide(); - $(source).unbind('keyup'); - return false; - })).append(']'); - } - else { - $(target).val(machine); - $(suffix).text(''); - } - }); - // Call keyup event on source element. - $(source).keyup(); - } - } - }, - - /** - * Transliterate a human-readable name to a machine name. - * - * The result should not contain any character matching settings.searchPattern, - * invalid characters are typically replaced with settings.replaceToken. - */ - transliterate: function (source, settings) { - var searchPattern = new RegExp(settings.searchPattern, 'g'); - return source.toLowerCase().replace(searchPattern, settings.replaceToken); - } -}; - })(jQuery); diff --git a/modules/system/system.module b/modules/system/system.module index 7466480c4..88c9c94c7 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -347,6 +347,18 @@ function system_element_info() { '#theme' => 'textfield', '#theme_wrappers' => array('form_element'), ); + $types['machine_name'] = array( + '#input' => TRUE, + '#default_value' => NULL, + '#required' => TRUE, + '#maxlength' => 64, + '#size' => 60, + '#autocomplete_path' => FALSE, + '#process' => array('form_process_machine_name', 'ajax_process_form'), + '#element_validate' => array('form_validate_machine_name'), + '#theme' => 'textfield', + '#theme_wrappers' => array('form_element'), + ); $types['password'] = array( '#input' => TRUE, '#size' => 60, diff --git a/modules/system/system.test b/modules/system/system.test index bc5f5593f..e6db7a13c 100644 --- a/modules/system/system.test +++ b/modules/system/system.test @@ -948,7 +948,7 @@ class DateTimeFunctionalTest extends DrupalWebTestCase { // Add custom date type. $this->clickLink(t('Add date type')); - $date_type = $this->randomName(8); + $date_type = strtolower($this->randomName(8)); $machine_name = 'machine_' . $date_type; $date_format = 'd.m.Y - H:i'; $edit = array( diff --git a/modules/taxonomy/taxonomy.admin.inc b/modules/taxonomy/taxonomy.admin.inc index 7b81db26d..7d314634a 100644 --- a/modules/taxonomy/taxonomy.admin.inc +++ b/modules/taxonomy/taxonomy.admin.inc @@ -137,30 +137,13 @@ function taxonomy_form_vocabulary($form, &$form_state, $edit = array()) { '#default_value' => $vocabulary->name, '#maxlength' => 255, '#required' => TRUE, - '#field_suffix' => ' <small id="edit-name-suffix"> </small>', - ); - $js_settings = array( - 'type' => 'setting', - 'data' => array( - 'machineReadableValue' => array( - 'name' => array( - 'text' => t('Machine name'), - 'target' => 'machine-name', - 'searchPattern' => '[^a-z0-9]+', - 'replaceToken' => '_', - ), - ), - ), ); $form['machine_name'] = array( - '#type' => 'textfield', - '#title' => t('Machine-readable name'), + '#type' => 'machine_name', '#default_value' => $vocabulary->machine_name, - '#maxlength' => 255, - '#description' => t('The unique machine-readable name for this vocabulary, used for theme templates. Can only contain lowercase letters, numbers, and underscores.'), - '#required' => TRUE, - '#attached' => array( - 'js' => array(drupal_get_path('module', 'system') . '/system.js', $js_settings), + '#maxlength' => 21, + '#machine_name' => array( + 'exists' => 'taxonomy_vocabulary_machine_name_load', ), ); $form['old_machine_name'] = array( @@ -190,34 +173,6 @@ function taxonomy_form_vocabulary($form, &$form_state, $edit = array()) { } /** - * Validation handler for the vocabulary form. - * - * @see taxonomy_form_vocabulary() - */ -function taxonomy_form_vocabulary_validate($form, &$form_state) { - if ($form_state['clicked_button']['#value'] != t('Delete') && isset($form_state['values']['machine_name'])) { - - // Restrict machine names to appropriate characters. - $machine_name = $form_state['values']['machine_name']; - if (!preg_match('!^[a-z0-9_]+$!', $form_state['values']['machine_name'])) { - form_set_error('machine_name', t('The machine-readable name must contain only lowercase letters, numbers, and underscores.')); - } - // Restrict machine names to 21 characters to avoid exceeding the limit - // for field names. - if (drupal_strlen($machine_name) > 21) { - form_set_error('machine_name', t('The machine-readable name must not exceed 21 characters.')); - } - - // Do not allow duplicate machine names. - $vocabularies = taxonomy_get_vocabularies(); - foreach ($vocabularies as $vocabulary) { - if ($machine_name == $vocabulary->machine_name && (!isset($form_state['values']['vid']) || $vocabulary->vid != $form_state['values']['vid'])) { - form_set_error('machine_name', t('This machine-readable name is already in use by another vocabulary and must be unique.')); - } - } - } -} -/** * Accept the form submission for a vocabulary and save the results. */ function taxonomy_form_vocabulary_submit($form, &$form_state) { diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test index 174e258ac..0a08c1bde 100644 --- a/modules/taxonomy/taxonomy.test +++ b/modules/taxonomy/taxonomy.test @@ -92,7 +92,7 @@ class TaxonomyVocabularyFunctionalTest extends TaxonomyWebTestCase { // Try to submit a vocabulary with a duplicate machine name. $edit['machine_name'] = $machine_name; $this->drupalPost('admin/structure/taxonomy/add', $edit, t('Save')); - $this->assertText(t('This machine-readable name is already in use by another vocabulary and must be unique.'), t('Duplicate machine name validation was successful')); + $this->assertText(t('The machine-readable name is already in use. It must be unique.')); // Try to submit an invalid machine name. $edit['machine_name'] = '!&^%'; |