Commit e550f841 authored by Dries's avatar Dries

- Patch #16204 by Thox: committed the collapsible form elements patch.

  NOTE: this patch works well, but the improved node edit form still has
        some rough edges.  It is important that we continue to improve
        usability.  Give it a try.
parent e16e048d
......@@ -1109,6 +1109,33 @@ function form_group($legend, $group, $description = NULL, $attributes = NULL) {
return '<fieldset' . drupal_attributes($attributes) .'>' . ($legend ? '<legend>'. $legend .'</legend>' : '') . $group . ($description ? '<div class="description">'. $description .'</div>' : '') . "</fieldset>\n";
}
/**
* Format a group of form items.
*
* @param $legend
* The label for the form item group.
* @param $group
* The form items within the group, as an HTML string.
* @param $collapsed
* A boolean value decided whether the group starts collapsed.
* @param $description
* Explanatory text to display after the form item group.
* @param $attributes
* An associative array of HTML attributes to add to the fieldset tag.
* @return
* A themed HTML string representing the form item group.
*/
function form_group_collapsible($legend, $group, $collapsed = FALSE, $description = NULL, $attributes = NULL) {
drupal_add_js('misc/collapse.js');
$attributes['class'] .= ' collapsible';
if ($collapsed) {
$attributes['class'] .= ' collapsed';
}
return '<fieldset' . drupal_attributes($attributes) .'>' . ($legend ? '<legend>'. $legend .'</legend>' : '') . $group . ($description ? '<div class="description">'. $description .'</div>' : '') . "</fieldset>\n";
}
/**
* Format a radio button.
*
......
if (isJsEnabled()) {
addLoadEvent(collapseAutoAttach);
}
function collapseAutoAttach() {
var fieldsets = document.getElementsByTagName('fieldset');
var legend, fieldset;
for (var i = 0; fieldset = fieldsets[i]; i++) {
if (!hasClass(fieldset, 'collapsible')) {
continue;
}
legend = fieldset.getElementsByTagName('legend');
if (legend.length == 0) {
continue;
}
legend = legend[0];
var a = document.createElement('a');
a.href = '#';
a.onclick = function() {
toggleClass(this.parentNode.parentNode, 'collapsed');
this.blur();
return false;
};
a.innerHTML = legend.innerHTML;
while (legend.hasChildNodes()) {
removeNode(legend.childNodes[0]);
}
legend.appendChild(a);
collapseEnsureErrorsVisible(fieldset);
}
}
function collapseEnsureErrorsVisible(fieldset) {
if (!hasClass(fieldset, 'collapsed')) {
return;
}
var inputs = [];
inputs = inputs.concat(fieldset.getElementsByTagName('input'));
inputs = inputs.concat(fieldset.getElementsByTagName('textarea'));
inputs = inputs.concat(fieldset.getElementsByTagName('select'));
for (var j = 0; j<3; j++) {
for (var i = 0; i < inputs[j].length; i++) {
if (hasClass(inputs[j][i], 'error')) {
return removeClass(fieldset, 'collapsed');
}
}
}
}
......@@ -586,3 +586,31 @@ input.form-autocomplete {
input.throbbing {
background-position: 100% -18px;
}
/*
** Collapsing fieldsets
*/
html.js fieldset.collapsed {
border-bottom-width: 0;
border-left-width: 0;
border-right-width: 0;
margin-bottom: 0;
}
html.js fieldset.collapsed * {
display: none;
}
html.js fieldset.collapsed legend,
html.js fieldset.collapsed legend * {
display: inline;
}
html.js fieldset.collapsible legend a {
padding-left: 15px;
background: url('menu-expanded.png') 5px 50% no-repeat;
}
html.js fieldset.collapsed legend a {
background-image: url('menu-collapsed.png');
}
......@@ -8,6 +8,7 @@ function isJsEnabled() {
!document.getElementsByTagName ||
!document.createElement ||
!document.createTextNode ||
!document.documentElement ||
!document.getElementById);
}
return document.jsEnabled;
......@@ -15,7 +16,7 @@ function isJsEnabled() {
// Global Killswitch
if (isJsEnabled()) {
document.documentElement.className = 'js';
}
/**
......
......@@ -254,7 +254,7 @@ function comment_nodeapi(&$node, $op, $arg = 0) {
if (user_access('administer comments')) {
$selected = isset($node->comment) ? $node->comment : variable_get("comment_$node->type", 2);
$output = form_radios('', 'comment', $selected, array(t('Disabled'), t('Read only'), t('Read/write')));
return form_group(t('User comments'), $output);
return form_group_collapsible(t('User comments'), $output, TRUE);
}
break;
......
......@@ -254,7 +254,7 @@ function comment_nodeapi(&$node, $op, $arg = 0) {
if (user_access('administer comments')) {
$selected = isset($node->comment) ? $node->comment : variable_get("comment_$node->type", 2);
$output = form_radios('', 'comment', $selected, array(t('Disabled'), t('Read only'), t('Read/write')));
return form_group(t('User comments'), $output);
return form_group_collapsible(t('User comments'), $output, TRUE);
}
break;
......
......@@ -725,7 +725,8 @@ function filter_form($name = 'format', $value = FILTER_FORMAT_DEFAULT) {
$output .= theme('filter_tips', $tips);
$output .= '</div>';
}
return theme('form_element', t('Input format'), $output, $extra, NULL, _form_get_error($name));
$group = theme('form_element', NULL, $output, $extra, NULL, _form_get_error($name));
return form_group_collapsible(t('Input format'), $group, TRUE);
}
else {
// Only one format available: use a hidden form item and only show tips.
......
......@@ -725,7 +725,8 @@ function filter_form($name = 'format', $value = FILTER_FORMAT_DEFAULT) {
$output .= theme('filter_tips', $tips);
$output .= '</div>';
}
return theme('form_element', t('Input format'), $output, $extra, NULL, _form_get_error($name));
$group = theme('form_element', NULL, $output, $extra, NULL, _form_get_error($name));
return form_group_collapsible(t('Input format'), $group, TRUE);
}
else {
// Only one format available: use a hidden form item and only show tips.
......
......@@ -1292,7 +1292,7 @@ function node_form($edit) {
$author .= form_textfield(t('Authored on'), 'date', $edit->date, 20, 25, NULL, NULL, TRUE);
$output .= '<div class="authored">';
$output .= form_group(t('Authoring information'), $author);
$output .= form_group_collapsible(t('Authoring information'), $author, TRUE);
$output .= "</div>\n";
$node_options = variable_get('node_options_'. $edit->type, array('status', 'promote'));
......@@ -1303,7 +1303,7 @@ function node_form($edit) {
$options .= form_checkbox(t('Create new revision'), 'revision', 1, isset($edit->revision) ? $edit->revision : in_array('revision', $node_options));
$output .= '<div class="options">';
$output .= form_group(t('Options'), $options);
$output .= form_group_collapsible(t('Publishing options'), $options, TRUE);
$output .= "</div>\n";
$extras .= implode('</div><div class="extra">', node_invoke_nodeapi($edit, 'form admin'));
......
......@@ -1292,7 +1292,7 @@ function node_form($edit) {
$author .= form_textfield(t('Authored on'), 'date', $edit->date, 20, 25, NULL, NULL, TRUE);
$output .= '<div class="authored">';
$output .= form_group(t('Authoring information'), $author);
$output .= form_group_collapsible(t('Authoring information'), $author, TRUE);
$output .= "</div>\n";
$node_options = variable_get('node_options_'. $edit->type, array('status', 'promote'));
......@@ -1303,7 +1303,7 @@ function node_form($edit) {
$options .= form_checkbox(t('Create new revision'), 'revision', 1, isset($edit->revision) ? $edit->revision : in_array('revision', $node_options));
$output .= '<div class="options">';
$output .= form_group(t('Options'), $options);
$output .= form_group_collapsible(t('Publishing options'), $options, TRUE);
$output .= "</div>\n";
$extras .= implode('</div><div class="extra">', node_invoke_nodeapi($edit, 'form admin'));
......
......@@ -201,7 +201,7 @@ function system_view_general() {
// We will use a random URL so there is no way a proxy or a browser could cache the "no such image" answer.
$group .= '<img style="position: relative; left: -1000em;" src="'. $base_url. '/system/test/'. user_password(20) .'.png" alt="" />';
$output = form_group(t('General settings'), $group);
$output = form_group_collapsible(t('General settings'), $group, TRUE);
// Error handling:
$period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200), 'format_interval');
......@@ -211,12 +211,12 @@ function system_view_general() {
$group .= form_select(t('Error reporting'), 'error_level', variable_get('error_level', 1), array(t('Write errors to the log'), t('Write errors to the log and to the screen')), t('Where Drupal, PHP and SQL errors are logged. On a production server it is recommended that errors are only written to the error log. On a test server it can be helpful to write logs to the screen.'));
$group .= form_select(t('Discard log entries older than'), 'watchdog_clear', variable_get('watchdog_clear', 604800), $period, t('The time log entries should be kept. Older entries will be automatically discarded. Requires crontab.'));
$output .= form_group(t('Error handling'), $group);
$output .= form_group_collapsible(t('Error handling'), $group, TRUE);
// Caching:
$group = form_radios(t('Page cache'), 'cache', variable_get('cache', CACHE_DISABLED), array(CACHE_DISABLED => t('Disabled (low-traffic sites)'), CACHE_ENABLED_STRICT => t('Strict (medium-traffic sites)'), CACHE_ENABLED_LOOSE => t('Loose (high-traffic sites)')), t("Drupal has a caching mechanism which stores dynamically generated web pages in a database. By caching a web page, Drupal does not have to create the page each time someone wants to view it, instead it takes only one SQL query to display it, reducing response time and the server's load. Only pages requested by \"anonymous\" users are cached. In order to reduce server load and save bandwidth, Drupal stores and sends cached pages compressed. Drupal supports strict caching and loose caching. Strict caching immediately deletes cached data as soon as it becomes invalid for any user. Loose caching delays the deletion of cached data to provide better performance for high traffic sites."));
$output .= form_group(t('Cache settings'), $group);
$output .= form_group_collapsible(t('Cache settings'), $group, TRUE);
// File system:
$directory_path = variable_get('file_directory_path', 'files');
......@@ -228,7 +228,7 @@ function system_view_general() {
$group = form_textfield(t('File system path'), 'file_directory_path', $directory_path, 70, 255, t('A file system path where the files will be stored. This directory has to exist and be writable by Drupal. If the download method is set to public this directory has to be relative to Drupal installation directory, and be accessible over the web. When download method is set to private this directory should not be accessible over the web. Changing this location after the site has been in use will cause problems so only change this setting on an existing site if you know what you are doing.'));
$group .= form_textfield(t('Temporary directory'), 'file_directory_temp', $directory_temp, 70, 255, t('Location where uploaded files will be kept during previews. Relative paths will be resolved relative to the file system path.'));
$group .= form_radios(t('Download method'), 'file_downloads', variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC), array(FILE_DOWNLOADS_PUBLIC => t('Public - files are available using http directly.'), FILE_DOWNLOADS_PRIVATE => t('Private - files are transferred by Drupal.')), t('If you want any sort of access control on the downloading of files, this needs to be set to <em>private</em>. You can change this at any time, however all download URLs will change and there may be unexpected problems so it is not recommended.'));
$output .= form_group(t('File system settings'), $group);
$output .= form_group_collapsible(t('File system settings'), $group, TRUE);
// Image handling:
$group = '';
......@@ -238,7 +238,7 @@ function system_view_general() {
}
$group .= image_toolkit_invoke('settings');
if ($group) {
$output .= form_group(t('Image handling'), $group);
$output .= form_group_collapsible(t('Image handling'), '<p>'.$group.'</p>', TRUE);
}
// Date settings:
......@@ -274,7 +274,7 @@ function system_view_general() {
$group .= form_select(t('Long date format'), 'date_format_long', variable_get('date_format_long', $datelong[0]), $datelongchoices, t('Longer date format used for detailed display.'));
$group .= form_select(t('First day of week'), 'date_first_day', variable_get('date_first_day', 0), array(0 => t('Sunday'), 1 => t('Monday'), 2 => t('Tuesday'), 3 => t('Wednesday'), 4 => t('Thursday'), 5 => t('Friday'), 6 => t('Saturday')), t('The first day of the week for calendar views.'));
$output .= form_group(t('Date settings'), $group);
$output .= form_group_collapsible(t('Date settings'), $group, TRUE);
return $output;
}
......
......@@ -201,7 +201,7 @@ function system_view_general() {
// We will use a random URL so there is no way a proxy or a browser could cache the "no such image" answer.
$group .= '<img style="position: relative; left: -1000em;" src="'. $base_url. '/system/test/'. user_password(20) .'.png" alt="" />';
$output = form_group(t('General settings'), $group);
$output = form_group_collapsible(t('General settings'), $group, TRUE);
// Error handling:
$period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200), 'format_interval');
......@@ -211,12 +211,12 @@ function system_view_general() {
$group .= form_select(t('Error reporting'), 'error_level', variable_get('error_level', 1), array(t('Write errors to the log'), t('Write errors to the log and to the screen')), t('Where Drupal, PHP and SQL errors are logged. On a production server it is recommended that errors are only written to the error log. On a test server it can be helpful to write logs to the screen.'));
$group .= form_select(t('Discard log entries older than'), 'watchdog_clear', variable_get('watchdog_clear', 604800), $period, t('The time log entries should be kept. Older entries will be automatically discarded. Requires crontab.'));
$output .= form_group(t('Error handling'), $group);
$output .= form_group_collapsible(t('Error handling'), $group, TRUE);
// Caching:
$group = form_radios(t('Page cache'), 'cache', variable_get('cache', CACHE_DISABLED), array(CACHE_DISABLED => t('Disabled (low-traffic sites)'), CACHE_ENABLED_STRICT => t('Strict (medium-traffic sites)'), CACHE_ENABLED_LOOSE => t('Loose (high-traffic sites)')), t("Drupal has a caching mechanism which stores dynamically generated web pages in a database. By caching a web page, Drupal does not have to create the page each time someone wants to view it, instead it takes only one SQL query to display it, reducing response time and the server's load. Only pages requested by \"anonymous\" users are cached. In order to reduce server load and save bandwidth, Drupal stores and sends cached pages compressed. Drupal supports strict caching and loose caching. Strict caching immediately deletes cached data as soon as it becomes invalid for any user. Loose caching delays the deletion of cached data to provide better performance for high traffic sites."));
$output .= form_group(t('Cache settings'), $group);
$output .= form_group_collapsible(t('Cache settings'), $group, TRUE);
// File system:
$directory_path = variable_get('file_directory_path', 'files');
......@@ -228,7 +228,7 @@ function system_view_general() {
$group = form_textfield(t('File system path'), 'file_directory_path', $directory_path, 70, 255, t('A file system path where the files will be stored. This directory has to exist and be writable by Drupal. If the download method is set to public this directory has to be relative to Drupal installation directory, and be accessible over the web. When download method is set to private this directory should not be accessible over the web. Changing this location after the site has been in use will cause problems so only change this setting on an existing site if you know what you are doing.'));
$group .= form_textfield(t('Temporary directory'), 'file_directory_temp', $directory_temp, 70, 255, t('Location where uploaded files will be kept during previews. Relative paths will be resolved relative to the file system path.'));
$group .= form_radios(t('Download method'), 'file_downloads', variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC), array(FILE_DOWNLOADS_PUBLIC => t('Public - files are available using http directly.'), FILE_DOWNLOADS_PRIVATE => t('Private - files are transferred by Drupal.')), t('If you want any sort of access control on the downloading of files, this needs to be set to <em>private</em>. You can change this at any time, however all download URLs will change and there may be unexpected problems so it is not recommended.'));
$output .= form_group(t('File system settings'), $group);
$output .= form_group_collapsible(t('File system settings'), $group, TRUE);
// Image handling:
$group = '';
......@@ -238,7 +238,7 @@ function system_view_general() {
}
$group .= image_toolkit_invoke('settings');
if ($group) {
$output .= form_group(t('Image handling'), $group);
$output .= form_group_collapsible(t('Image handling'), '<p>'.$group.'</p>', TRUE);
}
// Date settings:
......@@ -274,7 +274,7 @@ function system_view_general() {
$group .= form_select(t('Long date format'), 'date_format_long', variable_get('date_format_long', $datelong[0]), $datelongchoices, t('Longer date format used for detailed display.'));
$group .= form_select(t('First day of week'), 'date_first_day', variable_get('date_first_day', 0), array(0 => t('Sunday'), 1 => t('Monday'), 2 => t('Tuesday'), 3 => t('Wednesday'), 4 => t('Thursday'), 5 => t('Friday'), 6 => t('Saturday')), t('The first day of the week for calendar views.'));
$output .= form_group(t('Date settings'), $group);
$output .= form_group_collapsible(t('Date settings'), $group, TRUE);
return $output;
}
......
......@@ -383,7 +383,7 @@ function upload_form($node) {
$output .= form_button(t('Attach'), 'fileop');
}
return '<div class="attachments">'. form_group(t('Attachments'), $output, t('Changes made to the attachments are not permanent until you save this post. The first "listed" file will be included in RSS feeds.')) .'</div>';
return '<div class="attachments">'. form_group_collapsible(t('File Attachments'), $output, TRUE, t('Changes made to the attachments are not permanent until you save this post. The first "listed" file will be included in RSS feeds.')) .'</div>';
}
function upload_load($node) {
......
......@@ -383,7 +383,7 @@ function upload_form($node) {
$output .= form_button(t('Attach'), 'fileop');
}
return '<div class="attachments">'. form_group(t('Attachments'), $output, t('Changes made to the attachments are not permanent until you save this post. The first "listed" file will be included in RSS feeds.')) .'</div>';
return '<div class="attachments">'. form_group_collapsible(t('File Attachments'), $output, TRUE, t('Changes made to the attachments are not permanent until you save this post. The first "listed" file will be included in RSS feeds.')) .'</div>';
}
function upload_load($node) {
......
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