diff --git a/core/includes/form.inc b/core/includes/form.inc index 5f580fb..fde5712 100644 --- a/core/includes/form.inc +++ b/core/includes/form.inc @@ -2804,6 +2804,39 @@ function theme_fieldset($variables) { } /** + * Returns HTML for a details form element and its children. + * + * @param $variables + * An associative array containing: + * - element: An associative array containing the properties of the element. + * Properties used: #attributes, #children, #collapsed, #collapsible, + * #description, #id, #title, #value. + * + * @ingroup themeable + */ +function theme_details($variables) { + $element = $variables['element']; + element_set_attributes($element, array('id')); + _form_set_class($element, array('form-wrapper')); + + $output = ''; + if (!empty($element['#title'])) { + $output .= '' . $element['#title'] . ''; + } + $output .= '
'; + if (!empty($element['#description'])) { + $output .= '
' . $element['#description'] . '
'; + } + $output .= $element['#children']; + if (isset($element['#value'])) { + $output .= $element['#value']; + } + $output .= '
'; + $output .= "\n"; + return $output; +} + +/** * Returns HTML for a radio button form element. * * Note: The input "name" attribute needs to be sanitized before output, which @@ -3695,6 +3728,40 @@ function form_process_fieldset(&$element, &$form_state) { } /** + * Arranges details into groups. + * + * @param $element + * An associative array containing the properties and children of the + * details. 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 details belongs to. + * + * @return + * The processed element. + */ +function form_process_details(&$element, &$form_state) { + $parents = implode('][', $element['#parents']); + + // Each detail forms a new group. The #type 'vertical_tabs' basically only + // injects a new details element. + $form_state['groups'][$parents]['#group_exists'] = TRUE; + $element['#groups'] = &$form_state['groups']; + + // Process vertical tabs group member details. + if (isset($element['#group'])) { + // Add this details to the defined group (by reference). + $group = $element['#group']; + $form_state['groups'][$group][] = &$element; + } + + // Contains form element summary functionalities. + $element['#attached']['library'][] = array('system', 'drupal.form'); + + return $element; +} + +/** * Adds members of this group as actual elements for rendering. * * @param $element @@ -3766,6 +3833,77 @@ function form_pre_render_fieldset($element) { } /** + * Adds members of this group as actual elements for rendering. + * + * @param $element + * An associative array containing the properties and children of the + * details. + * + * @return + * The modified element with all group members. + */ +function form_pre_render_details($element) { + // The .form-wrapper class is required for #states to treat details like + // containers. + if (!isset($element['#attributes']['class'])) { + $element['#attributes']['class'] = array(); + } + + // Collapsible details + if (!empty($element['#collapsible'])) { + $element['#attached']['library'][] = array('system', 'drupal.collapse'); + $element['#attributes']['class'][] = 'collapsible'; + if (!empty($element['#collapsed'])) { + $element['#attributes']['class'][] = 'collapsed'; + } + } + + // Fieldsets may be rendered outside of a Form API context. + if (!isset($element['#parents']) || !isset($element['#groups'])) { + return $element; + } + // 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_details'] = 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_details'])) { + // 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; + } + } + + return $element; +} + +/** * Creates a group formatted as vertical tabs. * * @param $element diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc index 429e990..0ca1001 100644 --- a/core/modules/system/system.admin.inc +++ b/core/modules/system/system.admin.inc @@ -1609,7 +1609,7 @@ function system_performance_settings($form, &$form_state) { ); $form['caching'] = array( - '#type' => 'fieldset', + '#type' => 'details', '#title' => t('Caching'), ); diff --git a/core/modules/system/system.module b/core/modules/system/system.module index d1c314d..147c526 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -530,6 +530,14 @@ function system_element_info() { '#pre_render' => array('form_pre_render_fieldset'), '#theme_wrappers' => array('fieldset'), ); + $types['details'] = array( + '#collapsible' => FALSE, + '#collapsed' => FALSE, + '#value' => NULL, + '#process' => array('form_process_details', 'ajax_process_form'), + '#pre_render' => array('form_pre_render_details'), + '#theme_wrappers' => array('details'), + ); $types['vertical_tabs'] = array( '#theme_wrappers' => array('vertical_tabs'), '#default_tab' => '',