Index: includes/form.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/form.inc,v retrieving revision 1.416 diff -u -p -r1.416 form.inc --- includes/form.inc 5 Dec 2009 16:03:51 -0000 1.416 +++ includes/form.inc 11 Dec 2009 21:06:57 -0000 @@ -2472,32 +2472,38 @@ function form_process_tableselect($eleme * The processed element. */ function form_process_fieldset(&$element, &$form_state) { + // Process vertical tabs information. $parents = implode('][', $element['#parents']); // Add this fieldset to a group if one is set and if it's not being // added to itself. - if (isset($element['#group']) && $element['#group'] != $parents) { - if (isset($form_state['groups'][$element['#group']]) && !empty($form_state['groups'][$element['#group']]['#group_exists'])) { - // Trick drupal_render() into believing this has already been output. - // The group widget will rerender this later. This only happens when the - // group is actually defined ('#group_exists' is TRUE). This prevents - // fieldsets from disappearing when the group they are associated to - // does not exist. - // If the group does not exist yet, the element's #printed value is left - // as is. As soon as the group is processed (fieldsets are also groups; - // see below), this element's #printed value is set to TRUE to prevent - // rendering in the original context. + if (isset($element['#group'])) { + $group = $element['#group']; + // Trick drupal_render() into believing this has already been output. + // The group widget will rerender this later. This only happens when the + // group is actually defined ('#group_exists' is TRUE). This prevents + // fieldsets from disappearing when the group they are associated to + // does not exist. + // If the group does not exist yet, the element's #printed value is left + // as is. As soon as the group is processed (fieldsets are also groups; + // see below), this element's #printed value is set to TRUE to prevent + // rendering in the original context. + if ($element['#group'] != $parents && !empty($form_state['groups'][$group]['#group_exists'])) { $element['#printed'] = TRUE; } + else { + $form_state['groups'][$group]['#group_exists'] = TRUE; + } // Store a reference to this fieldset for the vertical tabs processing // function. - $form_state['groups'][$element['#group']][] = &$element; + $form_state['groups'][$group][] = &$element; } // Each fieldset can be a group itself and gets a reference to all // elements in its group. $form_state['groups'][$parents]['#group_exists'] = TRUE; + // There might already be elements associated with this group. Since the // group did not exist yet at the time they were added to this group, they // couldn't set #printed to TRUE (see above). We now know that this group @@ -2506,6 +2512,12 @@ function form_process_fieldset(&$element foreach (element_children($form_state['groups'][$parents]) as $key) { $form_state['groups'][$parents][$key]['#printed'] = TRUE; } + if (isset($element['#group'])) { + $group = $element['#group']; + foreach (element_children($form_state['groups'][$group]) as $key) { + $form_state['groups'][$group][$key]['#printed'] = TRUE; + } + } $element['#group_members'] = &$form_state['groups'][$parents]; // Contains form element summary functionalities. @@ -2599,11 +2611,8 @@ function form_process_vertical_tabs($ele * * @param $variables * An associative array containing: - * - * - element - * An associative array containing the properties and children of the - * fieldset. - * Properties used: #children. + * - element: An associative array containing the properties and children of the + * fieldset. Properties used: #children. * * @return * A themed HTML string representing the form element. Index: modules/filter/filter.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/filter/filter.admin.inc,v retrieving revision 1.53 diff -u -p -r1.53 filter.admin.inc --- modules/filter/filter.admin.inc 8 Dec 2009 03:10:51 -0000 1.53 +++ modules/filter/filter.admin.inc 11 Dec 2009 21:51:30 -0000 @@ -105,18 +105,16 @@ function filter_admin_format_page($forma */ function filter_admin_format_form($form, &$form_state, $format) { $is_fallback = ($format->format == filter_fallback_format()); - if ($is_fallback) { - $help = t('All roles for this text format must be enabled and cannot be changed.'); - } $form['#format'] = $format; $form['#tree'] = TRUE; + $form['#attached']['js'][] = drupal_get_path('module', 'filter') . '/filter.admin.js'; + $form['#attached']['css'][] = drupal_get_path('module', 'filter') . '/filter.css'; $form['name'] = array( '#type' => 'textfield', '#title' => t('Name'), '#default_value' => $format->name, - '#description' => t('Specify a unique name for this text format.'), '#required' => TRUE, ); @@ -124,55 +122,112 @@ function filter_admin_format_form($form, $form['roles'] = array( '#type' => 'checkboxes', '#title' => t('Roles'), - '#description' => $is_fallback ? $help : t('Choose which roles may use this text format. Note that roles with the "administer filters" permission can always use all text formats.'), '#options' => user_roles(), '#default_value' => array_keys(filter_get_roles_by_format($format)), '#disabled' => $is_fallback, ); + if ($is_fallback) { + $form['roles']['#description'] = t('All roles for this text format must be enabled and cannot be changed.'); + } - // Table with filters + // Retrieve available filters and load all configured filters for existing + // text formats. $filter_info = filter_get_filters(); - // Load all configured filters for existing text formats. $filters = !empty($format->format) ? filter_list_format($format->format) : array(); - $form['filters'] = array( - '#type' => 'fieldset', - '#title' => t('Filters'), - '#description' => t('Choose the filters that will be used in this text format.'), - ); - + // Prepare filters for form sections. foreach ($filter_info as $name => $filter) { // Create an empty filter object for new/unconfigured filters. if (!isset($filters[$name])) { $filters[$name] = new stdClass; $filters[$name]->status = 0; - $filters[$name]->weight = 0; + $filters[$name]->weight = $filter['weight']; $filters[$name]->settings = array(); } - $form['filters'][$name]['#filter'] = $filters[$name]; - $form['filters'][$name]['status'] = array( + } + $form['#filters'] = $filters; + + // Filter status. + $form['filters']['status'] = array( + '#type' => 'item', + '#title' => t('Enabled filters'), + '#prefix' => '
' . t('No guidelines available.') . '
'; + if (empty($tiplist)) { + $form['tips']['#markup'] = t('No guidelines available.'); } else { - $tiplist .= theme('filter_tips_more_info'); + $form['tips']['#markup'] = $tiplist . theme('filter_tips_more_info'); } - $group = '' . t('These are the guidelines that users will see for posting in this text format. They are automatically generated from the filter settings.') . '
'; - $group .= $tiplist; - $form['tips'] = array('#markup' => '' . t("Control which HTML tags and other formatting can be used for text input. Don't allow too much formatting for untrusted users. This can be a serious security risk.") . '
'; $output .= '' . t('Text formats are presented in the order you arrange them below. Configure a text format to change its behavior.') . '
'; return $output; + case 'admin/config/content/formats/%': - return '' . t('Every filter performs one particular change on the user input, for example stripping out malicious HTML or making URLs clickable. Choose which filters you want to apply to text in this format. If you notice some filters are causing conflicts in the output, you can rearrange them.', array('@rearrange' => url('admin/config/content/formats/' . $arg[4] . '/order'))) . '
'; - case 'admin/config/content/formats/%/configure': - return '' . t('If you cannot find the settings for a certain filter, make sure you have enabled it on the edit tab first.', array('@url' => url('admin/config/content/formats/' . $arg[4]))) . '
'; - case 'admin/config/content/formats/%/order': - $output = '' . t('Because of the flexible filtering system, you might encounter a situation where one filter prevents another from doing its job. For example: a word in an URL gets converted into a glossary term, before the URL can be converted to a clickable link. When this happens, rearrange the order of the filters.') . '
'; - $output .= '' . t("Filters are executed from top-to-bottom. To change the order of the filters, modify the values in the Weight column or grab a drag-and-drop handle under the Name column and drag filters to new locations in the list. (Grab a handle by clicking and holding the mouse while hovering over a handle icon.) Remember that your changes will not be saved until you click the Save configuration button at the bottom of the page.") . '
'; + $output = '' . t('A text format contains filters that change the user input, for example stripping out malicious HTML or making URLs clickable. Filters are executed from top to bottom and the order is important, since one filter may prevent another filter from doing its job. For example, when URLs are converted into links before disallowed HTML tags are removed, all links may be removed. When this happens, the order of filters may need to be re-arranged.') . '
'; return $output; } } @@ -49,8 +46,8 @@ function filter_theme() { 'render element' => 'form', 'file' => 'filter.admin.inc', ), - 'filter_admin_order' => array( - 'render element' => 'form', + 'filter_admin_format_filter_order' => array( + 'render element' => 'element', 'file' => 'filter.admin.inc', ), 'filter_tips' => array( @@ -106,29 +103,6 @@ function filter_menu() { 'access arguments' => array('administer filters'), 'file' => 'filter.admin.inc', ); - $items['admin/config/content/formats/%filter_format/edit'] = array( - 'title' => 'Edit', - 'type' => MENU_DEFAULT_LOCAL_TASK, - 'weight' => 0, - ); - $items['admin/config/content/formats/%filter_format/configure'] = array( - 'title' => 'Configure', - 'page callback' => 'filter_admin_configure_page', - 'page arguments' => array(4), - 'access arguments' => array('administer filters'), - 'type' => MENU_LOCAL_TASK, - 'weight' => 1, - 'file' => 'filter.admin.inc', - ); - $items['admin/config/content/formats/%filter_format/order'] = array( - 'title' => 'Rearrange', - 'page callback' => 'filter_admin_order_page', - 'page arguments' => array(4), - 'access arguments' => array('administer filters'), - 'type' => MENU_LOCAL_TASK, - 'weight' => 2, - 'file' => 'filter.admin.inc', - ); $items['admin/config/content/formats/%filter_format/delete'] = array( 'title' => 'Delete text format', 'page callback' => 'drupal_get_form', @@ -200,37 +174,25 @@ function filter_format_save(&$format) { $return = drupal_write_record('filter_format', $format, 'format'); } - // Get the current filters in the format, to add new filters to the bottom. - $current = ($return != SAVED_NEW ? filter_list_format($format->format) : array()); $filter_info = filter_get_filters(); // Programmatic saves may not contain any filters. if (!isset($format->filters)) { $format->filters = array(); } foreach ($filter_info as $name => $filter) { - // As of now, only programmatic saves may contain weight (see below). If - // there is no weight, either fall back to the currently stored weight or - // add new filters to the bottom. + // Add new filters without weight to the bottom. if (!isset($format->filters[$name]['weight'])) { - $format->filters[$name]['weight'] = isset($current[$name]->weight) ? $current[$name]->weight : 10; + $format->filters[$name]['weight'] = 10; } $format->filters[$name]['status'] = isset($format->filters[$name]['status']) ? $format->filters[$name]['status'] : 0; $format->filters[$name]['module'] = $filter['module']; - // Since filter configuration/order lives on separate pages, there may be no - // filter settings contained. In that case, we either fall back to currently - // stored settings, default settings (if existent), or an empty array. - // @see http://drupal.org/node/558666 // If settings were passed, only ensure default settings. if (isset($format->filters[$name]['settings'])) { if (isset($filter['default settings'])) { $format->filters[$name]['settings'] = array_merge($filter['default settings'], $format->filters[$name]['settings']); } } - // If we have existing settings, take them over directly. - elseif (isset($current[$name]->settings)) { - $format->filters[$name]['settings'] = $current[$name]->settings; - } // Otherwise, use default settings or fall back to an empty array. else { $format->filters[$name]['settings'] = isset($filter['default settings']) ? $filter['default settings'] : array(); @@ -503,9 +465,14 @@ function filter_get_filters() { foreach (module_implements('filter_info') as $module) { $info = module_invoke($module, 'filter_info'); if (isset($info) && is_array($info)) { - // Assign the name of the module implementing the filters. + // Assign the name of the module implementing the filters and ensure + // default values. foreach (array_keys($info) as $name) { $info[$name]['module'] = $module; + $info[$name] += array( + 'description' => '', + 'weight' => 0, + ); } $filters = array_merge($filters, $info); } @@ -895,7 +862,6 @@ function theme_filter_guidelines($variab function filter_filter_info() { $filters['filter_html'] = array( 'title' => t('Limit allowed HTML tags'), - 'description' => t('Allows you to restrict the HTML tags the user can use. It will also remove harmful content such as JavaScript events, JavaScript URLs and CSS styles from those tags that are not removed.'), 'process callback' => '_filter_html', 'settings callback' => '_filter_html_settings', 'default settings' => array( @@ -904,16 +870,15 @@ function filter_filter_info() { 'filter_html_nofollow' => 0, ), 'tips callback' => '_filter_html_tips', + 'weight' => -10, ); $filters['filter_autop'] = array( - 'title' => t('Convert line breaks'), - 'description' => t('Converts line breaks into HTML (i.e. <br> and <p>) tags.'), + 'title' => t('Convert line breaks into HTML (i.e.<br> and <p>)'),
'process callback' => '_filter_autop',
'tips callback' => '_filter_autop_tips',
);
$filters['filter_url'] = array(
'title' => t('Convert URLs into links'),
- 'description' => t('Turns web and e-mail addresses into clickable links.'),
'process callback' => '_filter_url',
'settings callback' => '_filter_url_settings',
'default settings' => array(
@@ -922,15 +887,15 @@ function filter_filter_info() {
'tips callback' => '_filter_url_tips',
);
$filters['filter_htmlcorrector'] = array(
- 'title' => t('Correct broken HTML'),
- 'description' => t('Corrects faulty and chopped off HTML in postings.'),
+ 'title' => t('Correct faulty and chopped off HTML'),
'process callback' => '_filter_htmlcorrector',
+ 'weight' => 10,
);
$filters['filter_html_escape'] = array(
- 'title' => t('Escape all HTML'),
- 'description' => t('Escapes all HTML tags, so they will be visible instead of being effective.'),
+ 'title' => t('Escape all HTML and make it visible instead of being effective'),
'process callback' => '_filter_html_escape',
'tips callback' => '_filter_html_escape_tips',
+ 'weight' => -10,
);
return $filters;
}
@@ -943,21 +908,18 @@ function _filter_html_settings($form, &$
'#type' => 'textfield',
'#title' => t('Allowed HTML tags'),
'#default_value' => isset($filter->settings['allowed_html']) ? $filter->settings['allowed_html'] : $defaults['allowed_html'],
- '#size' => 64,
'#maxlength' => 1024,
- '#description' => t('Specify a list of tags which should not be stripped. (Note that JavaScript event attributes are always stripped.)'),
+ '#description' => t('A list of HTML tags that can be used. JavaScript event attributes, JavaScript URLs, and CSS are always stripped.'),
);
$settings['filter_html_help'] = array(
'#type' => 'checkbox',
- '#title' => t('Display HTML help'),
+ '#title' => t('Display basic HTML help in long filter tips'),
'#default_value' => isset($filter->settings['filter_html_help']) ? $filter->settings['filter_html_help'] : $defaults['filter_html_help'],
- '#description' => t('If enabled, Drupal will display some basic HTML help in the long filter tips.'),
);
$settings['filter_html_nofollow'] = array(
'#type' => 'checkbox',
- '#title' => t('Spam link deterrent'),
+ '#title' => t('Add rel="nofollow" to all links'),
'#default_value' => isset($filter->settings['filter_html_nofollow']) ? $filter->settings['filter_html_nofollow'] : $defaults['filter_html_nofollow'],
- '#description' => t('If enabled, Drupal will add rel="nofollow" to all links, as a measure to reduce the effectiveness of spam links. Note: this will also prevent valid links from being followed by search engines, therefore it is likely most effective when enabled for anonymous users.'),
);
return $settings;
}
@@ -1089,7 +1051,9 @@ function _filter_url_settings($form, &$f
'#type' => 'textfield',
'#title' => t('Maximum link text length'),
'#default_value' => isset($filter->settings['filter_url_length']) ? $filter->settings['filter_url_length'] : $defaults['filter_url_length'],
+ '#size' => 5,
'#maxlength' => 4,
+ '#field_suffix' => t('characters'),
'#description' => t('URLs longer than this number of characters will be truncated to prevent long strings that break formatting. The link itself will be retained; just the text portion of the link will be truncated.'),
);
return $settings;
Index: modules/filter/filter.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.test,v
retrieving revision 1.52
diff -u -p -r1.52 filter.test
--- modules/filter/filter.test 8 Dec 2009 03:10:51 -0000 1.52
+++ modules/filter/filter.test 8 Dec 2009 04:23:10 -0000
@@ -222,39 +222,22 @@ class FilterAdminTestCase extends Drupal
$this->assertTrue(filter_access(filter_format_load($full), $this->admin_user), t('Admin user may use Full HTML.'));
$this->assertFalse(filter_access(filter_format_load($full), $this->web_user), t('Web user may not use Full HTML.'));
- // Verify that disabled filters are not displayed.
- $edit = array();
- $edit['filters[filter_url][status]'] = FALSE;
- $this->drupalPost('admin/config/content/formats/' . $filtered, $edit, t('Save configuration'));
- $this->drupalGet('admin/config/content/formats/' . $filtered . '/configure');
- $this->assertNoText(t('Convert URLs into links'), t('Disabled URL filter cannot be configured.'));
- $this->drupalGet('admin/config/content/formats/' . $filtered . '/order');
- $this->assertNoText(t('Convert URLs into links'), t('Disabled URL filter cannot be re-ordered.'));
- $edit = array();
- $edit['filters[filter_url][status]'] = 1;
- $this->drupalPost('admin/config/content/formats/' . $filtered, $edit, t('Save configuration'));
- $this->drupalGet('admin/config/content/formats/' . $filtered . '/configure');
- $this->assertText(t('Convert URLs into links'), t('Enabled URL filter can be configured.'));
- $this->drupalGet('admin/config/content/formats/' . $filtered . '/order');
- $this->assertText(t('Convert URLs into links'), t('Enabled URL filter can be re-ordered.'));
-
// Add an additional tag.
$edit = array();
- $edit['settings[filter_html][allowed_html]'] = ' -
-
-
';
- $this->drupalPost('admin/config/content/formats/' . $filtered . '/configure', $edit, t('Save configuration'));
- $this->assertText(t('The configuration options have been saved.'), t('Allowed HTML tag added.'));
-
- $this->assertRaw(htmlentities($edit['settings[filter_html][allowed_html]']), t('Tag displayed.'));
+ $edit['filters[filter_html][settings][allowed_html]'] = ' -
-
-
';
+ $this->drupalPost('admin/config/content/formats/' . $filtered, $edit, t('Save configuration'));
+ $this->assertFieldByName('filters[filter_html][settings][allowed_html]', $edit['filters[filter_html][settings][allowed_html]'], t('Allowed HTML tag added.'));
$result = db_query('SELECT * FROM {cache_filter}')->fetchObject();
$this->assertFalse($result, t('Cache cleared.'));
// Reorder filters.
$edit = array();
- $edit['weights[' . $second_filter . ']'] = 1;
- $edit['weights[' . $first_filter . ']'] = 2;
- $this->drupalPost('admin/config/content/formats/' . $filtered . '/order', $edit, t('Save configuration'));
- $this->assertText(t('The filter ordering has been saved.'), t('Order saved successfully.'));
+ $edit['filters[' . $second_filter . '][weight]'] = 1;
+ $edit['filters[' . $first_filter . '][weight]'] = 2;
+ $this->drupalPost(NULL, $edit, t('Save configuration'));
+ $this->assertFieldByName('filters[' . $second_filter . '][weight]', 1, t('Order saved successfully.'));
+ $this->assertFieldByName('filters[' . $first_filter . '][weight]', 2, t('Order saved successfully.'));
$result = db_query('SELECT * FROM {filter} WHERE format = :format ORDER BY weight ASC', array(':format' => $filtered));
$filters = array();
@@ -333,22 +316,24 @@ class FilterAdminTestCase extends Drupal
// Clean up.
// Allowed tags.
$edit = array();
- $edit['settings[filter_html][allowed_html]'] = ' -
-
- ';
- $this->drupalPost('admin/config/content/formats/' . $filtered . '/configure', $edit, t('Save configuration'));
- $this->assertText(t('The configuration options have been saved.'), t('Changes reverted.'));
+ $edit['filters[filter_html][settings][allowed_html]'] = '
-
-
- ';
+ $this->drupalPost('admin/config/content/formats/' . $filtered, $edit, t('Save configuration'));
+ $this->assertFieldByName('filters[filter_html][settings][allowed_html]', $edit['filters[filter_html][settings][allowed_html]'], t('Changes reverted.'));
// Full HTML.
$edit = array();
$edit['roles[2]'] = FALSE;
$this->drupalPost('admin/config/content/formats/' . $full, $edit, t('Save configuration'));
$this->assertRaw(t('The text format %format has been updated.', array('%format' => $format->name)), t('Full HTML format successfully reverted.'));
+ $this->assertFieldByName('roles[2]', $edit['roles[2]'], t('Changes reverted.'));
// Filter order.
$edit = array();
- $edit['weights[' . $second_filter . ']'] = 2;
- $edit['weights[' . $first_filter . ']'] = 1;
- $this->drupalPost('admin/config/content/formats/' . $filtered . '/order', $edit, t('Save configuration'));
- $this->assertText(t('The filter ordering has been saved.'), t('Order successfully reverted.'));
+ $edit['filters[' . $second_filter . '][weight]'] = 2;
+ $edit['filters[' . $first_filter . '][weight]'] = 1;
+ $this->drupalPost('admin/config/content/formats/' . $filtered, $edit, t('Save configuration'));
+ $this->assertFieldByName('filters[' . $second_filter . '][weight]', $edit['filters[' . $second_filter . '][weight]'], t('Changes reverted.'));
+ $this->assertFieldByName('filters[' . $first_filter . '][weight]', $edit['filters[' . $first_filter . '][weight]'], t('Changes reverted.'));
}
/**