Commit 516d24d1 authored by Dries's avatar Dries

- Patch #558666 by sun, dropcube: revamp text format/filter configuration for better usability.

parent 5db74af7
......@@ -4984,7 +4984,7 @@ function drupal_render(&$elements) {
}
// Do not print elements twice.
if (isset($elements['#printed']) && $elements['#printed']) {
if (!empty($elements['#printed'])) {
return;
}
......@@ -5016,6 +5016,11 @@ function drupal_render(&$elements) {
}
}
// Allow #pre_render to abort rendering.
if (!empty($elements['#printed'])) {
return;
}
// Get the children of the element, sorted by weight.
$children = element_children($elements, TRUE);
......
......@@ -2463,9 +2463,10 @@ function form_process_tableselect($element) {
* Adds fieldsets to the specified group or adds group members to this
* fieldset.
*
* @param $element
* @param &$element
* An associative array containing the properties and children of the
* fieldset.
* fieldset. Note that $element must be taken by reference here, so processed
* child elements are taken over into $form_state.
* @param $form_state
* The $form_state array for the form this fieldset belongs to.
* @return
......@@ -2474,39 +2475,17 @@ function form_process_tableselect($element) {
function form_process_fieldset(&$element, &$form_state) {
$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.
$element['#printed'] = TRUE;
}
// Store a reference to this fieldset for the vertical tabs processing
// function.
$form_state['groups'][$element['#group']][] = &$element;
}
// Each fieldset can be a group itself and gets a reference to all
// elements in its group.
// Each fieldset forms a new group. The #type 'vertical_tabs' basically only
// injects a new fieldset.
$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
// does in fact exist and set #printed to TRUE to prevent rendering in the
// original context.
foreach (element_children($form_state['groups'][$parents]) as $key) {
$form_state['groups'][$parents][$key]['#printed'] = TRUE;
$element['#groups'] = &$form_state['groups'];
// Process vertical tabs group member fieldsets.
if (isset($element['#group'])) {
// Add this fieldset to the defined group (by reference).
$group = $element['#group'];
$form_state['groups'][$group][] = &$element;
}
$element['#group_members'] = &$form_state['groups'][$parents];
// Contains form element summary functionalities.
$element['#attached']['js']['misc/form.js'] = array('weight' => JS_LIBRARY + 1);
......@@ -2534,22 +2513,47 @@ function form_process_fieldset(&$element, &$form_state) {
* @param $element
* An associative array containing the properties and children of the
* fieldset.
*
* @return
* The modified element with all group members.
*/
function form_pre_render_fieldset($element) {
if (!empty($element['#group_members'])) {
// Add the group members to this fieldset for rendering purposes only.
foreach (element_children($element['#group_members']) as $key) {
// This was set in form_process_fieldset so that fieldsets which are
// added to groups are not rendered at their original location.
// drupal_render_children() will set this back to TRUE.
unset($element['#group_members'][$key]['#printed']);
$element[] = &$element['#group_members'][$key];
// Inject group member elements belonging to this group.
$parents = implode('][', $element['#parents']);
$children = element_children($element['#groups'][$parents]);
if (!empty($children)) {
foreach ($children as $key) {
// Break references and indicate that the element should be rendered as
// group member.
$child = (array) $element['#groups'][$parents][$key];
$child['#group_fieldset'] = TRUE;
// Inject the element as new child element.
$element[] = $child;
$sort = TRUE;
}
// Re-sort the element's children if we injected group member elements.
if (isset($sort)) {
$element['#sorted'] = FALSE;
}
}
if (isset($element['#group'])) {
$group = $element['#group'];
// If this element belongs to a group, but the group-holding element does
// not exist, we need to render it (at its original location).
if (!isset($element['#groups'][$group]['#group_exists'])) {
// Intentionally empty to clarify the flow; we simply return $element.
}
// If we injected this element into the group, then we want to render it.
elseif (!empty($element['#group_fieldset'])) {
// Intentionally empty to clarify the flow; we simply return $element.
}
// Otherwise, this element belongs to a group and the group exists, so we do
// not render it.
elseif (element_children($element['#groups'][$group])) {
$element['#printed'] = TRUE;
}
// Resort the element's children after the group members have been added.
$element['#sorted'] = FALSE;
}
return $element;
......@@ -2567,10 +2571,8 @@ function form_pre_render_fieldset($element) {
* The processed element.
*/
function form_process_vertical_tabs($element, &$form_state) {
// To save us from modifying the existing element and changing its #type,
// a new form element is created as a child. The default #process hooks
// are called automatically by the form renderer and we don't have to do
// that manually.
// Inject a new fieldset as child, so that form_process_fieldset() processes
// this fieldset like any other fieldset.
$element['group'] = array(
'#type' => 'fieldset',
'#theme_wrappers' => array(),
......@@ -2599,11 +2601,8 @@ function form_process_vertical_tabs($element, &$form_state) {
*
* @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.
......
......@@ -259,7 +259,7 @@ function block_admin_configure($form, &$form_state, $module, $delta) {
'#title' => t('Pages'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#group' => 'visibility_settings',
'#group' => 'visibility',
);
$access = user_access('use PHP for settings');
......@@ -312,7 +312,7 @@ function block_admin_configure($form, &$form_state, $module, $delta) {
'#title' => t('Content types'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#group' => 'visibility_settings',
'#group' => 'visibility',
);
$form['visibility']['node_type']['types'] = array(
'#type' => 'checkboxes',
......@@ -333,7 +333,7 @@ function block_admin_configure($form, &$form_state, $module, $delta) {
'#title' => t('Roles'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#group' => 'visibility_settings',
'#group' => 'visibility',
);
$form['visibility']['role']['roles'] = array(
'#type' => 'checkboxes',
......@@ -349,7 +349,7 @@ function block_admin_configure($form, &$form_state, $module, $delta) {
'#title' => t('Users'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#group' => 'visibility_settings',
'#group' => 'visibility',
);
$form['visibility']['user']['custom'] = array(
'#type' => 'radios',
......
This diff is collapsed.
// $Id$
(function ($) {
/**
* Shows the vertical tab pane.
*/
Drupal.verticalTab.prototype.tabShow = function () {
// Display the tab.
this.item.show();
// Update .first marker for items. We need recurse from parent to retain the
// actual DOM element order as jQuery implements sortOrder, but not as public
// method.
this.item.parent().children('.vertical-tab-button').removeClass('first')
.filter(':visible:first').addClass('first');
// Display the fieldset.
this.fieldset.removeClass('filter-settings-hidden').show();
// Focus this tab.
this.focus();
return this;
};
/**
* Hides the vertical tab pane.
*/
Drupal.verticalTab.prototype.tabHide = function () {
// Hide this tab.
this.item.hide();
// Update .first marker for items. We need recurse from parent to retain the
// actual DOM element order as jQuery implements sortOrder, but not as public
// method.
this.item.parent().children('.vertical-tab-button').removeClass('first')
.filter(':visible:first').addClass('first');
// Hide the fieldset.
this.fieldset.addClass('filter-settings-hidden').hide();
// Focus the first visible tab (if there is one).
var $firstTab = this.fieldset.siblings('.vertical-tabs-pane:not(.filter-settings-hidden):first');
if ($firstTab.length) {
$firstTab.data('verticalTab').focus();
}
return this;
};
Drupal.behaviors.filterStatus = {
attach: function (context, settings) {
$('#filters-status-wrapper input.form-checkbox', context).once('filter-status', function () {
var $checkbox = $(this);
// Retrieve the tabledrag row belonging to this filter.
var $row = $('#' + $checkbox.attr('id').replace(/-status$/, '-weight'), context).closest('tr');
// Retrieve the vertical tab belonging to this filter.
var tab = $('#' + $checkbox.attr('id').replace(/-status$/, '-settings'), context).data('verticalTab');
// Bind click handler to this checkbox to conditionally show and hide the
// filter's tableDrag row and vertical tab pane.
$checkbox.bind('click.filterUpdate', function () {
if ($checkbox.is(':checked')) {
$row.show();
if (tab) {
tab.tabShow().updateSummary();
}
}
else {
$row.hide();
if (tab) {
tab.tabHide().updateSummary();
}
}
// Restripe table after toggling visibility of table row.
Drupal.tableDrag['filter-order'].restripeTable();
});
// Attach summary for configurable filters (only for screen-readers).
if (tab) {
tab.fieldset.setSummary(function (tabContext) {
return $checkbox.is(':checked') ? Drupal.t('Enabled') : Drupal.t('Disabled');
});
}
// Trigger our bound click handler to update elements to initial state.
$checkbox.trigger('click.filterUpdate');
});
}
};
})(jQuery);
......@@ -35,3 +35,14 @@
.text-format-wrapper .description {
margin-top: 0.5em;
}
#filter-order tr .form-item {
padding: 0.5em 0 0 3em;
white-space: normal;
}
#filter-order tr .form-type-checkbox .description {
padding: 0 0 0 2.5em;
}
input#edit-filters-filter-html-settings-allowed-html {
width: 100%;
}
This diff is collapsed.
......@@ -222,39 +222,22 @@ class FilterAdminTestCase extends DrupalWebTestCase {
$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]'] = '<a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <quote>';
$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]'] = '<a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <quote>';
$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 DrupalWebTestCase {
// Clean up.
// Allowed tags.
$edit = array();
$edit['settings[filter_html][allowed_html]'] = '<a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>';
$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]'] = '<a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>';
$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.'));
}
/**
......
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