diff -rupN modules/content_multigroup/content_multigroup.css modules/content_multigroup/content_multigroup.css --- modules/content_multigroup/content_multigroup.css 2008-10-14 17:16:50.000000000 +0200 +++ modules/content_multigroup/content_multigroup.css 2008-12-11 08:08:41.000000000 +0100 @@ -2,8 +2,13 @@ label.content-multigroup { font-weight:bold; -} +} /* Not styled by default, but available to style */ hr.content-multigroup { -} \ No newline at end of file +} + +/* Inline field labels visible within the content of multigroups. */ +.multigroup .field .field-label-inline { + visibility:visible; +} diff -rupN modules/content_multigroup/content_multigroup.module modules/content_multigroup/content_multigroup.module --- modules/content_multigroup/content_multigroup.module 2008-10-22 13:02:41.000000000 +0200 +++ modules/content_multigroup/content_multigroup.module 2008-12-16 20:35:45.000000000 +0100 @@ -37,6 +37,9 @@ function content_multigroup_theme() { 'content_multigroup_display_simple' => array( 'arguments' => array('element' => NULL), ), + 'content_multigroup_display_fieldset' => array( + 'arguments' => array('element' => NULL), + ), 'content_multigroup_display_hr' => array( 'arguments' => array('element' => NULL), ), @@ -47,6 +50,15 @@ function content_multigroup_theme() { } /** + * Implementation of hook_elements(). + */ +function content_multigroup_elements() { + return array( + 'content_multigroup_display_fieldset' => array('#value' => NULL), + ); +} + +/** * Implementation of hook_fieldgroup_types(). */ function content_multigroup_fieldgroup_types() { @@ -61,7 +73,7 @@ function content_multigroup_fieldgroup_d module_load_include('inc', 'content', 'includes/content.admin'); $settings = array('multigroup' => array('multiple' => 1)); foreach (array_keys(content_build_modes()) as $key) { - $settings['multigroup']['display_settings'][$key]['format'] = 'fieldset'; + $settings['display'][$key]['format'] = 'fieldset'; } return $settings; } @@ -108,12 +120,12 @@ function content_multigroup_form_alter(& content_multigroup_field_overview_form($form, $form_state); $form['#validate'][] = 'content_multigroup_field_overview_form_validate'; } - elseif ($form_id == 'content_display_overview_form') { + elseif ($form_id == 'content_display_overview_form' && !empty($form['#groups'])) { content_multigroup_display_overview_form($form, $form_state, $form_id); $form['#submit'] = array_merge(array('content_multigroup_display_overview_form_submit'), $form['#submit']); } elseif ($form_id == 'fieldgroup_group_edit_form') { - return content_multigroup_group_edit_form($form, $form_state, $form_id); + content_multigroup_group_edit_form($form, $form_state, $form_id); } } @@ -180,39 +192,37 @@ function content_multigroup_field_overvi } } - if (!empty($fields)) { - foreach ($fields as $field_name => $field) { - $new_group = $form_values[$field_name]['parent']; - $old_group = $form_values[$field_name]['prev_parent']; - if (!empty($new_group) && isset($groups[$new_group]) && $groups[$new_group]['group_type'] == 'multigroup') { - $allowed_in = content_multigroup_allowed_in($field, $groups[$new_group]); - if (!$allowed_in['allowed']) { - form_set_error($field_name, $allowed_in['message']); - } - else { - if (!empty($allowed_in['message'])) { - drupal_set_message($allowed_in['message']); - } - module_load_include('inc', 'content', 'includes/content.crud'); - $content_type = content_types($type_name); - $multiple = $groups[$new_group]['settings']['multigroup']['multiple']; - $multiple_values = content_multigroup_multiple_values(); - $field = $content_type['fields'][$field_name]; - $field['multiple'] = $multiple; - $field = content_field_instance_collapse($field); - content_field_instance_update($field); - drupal_set_message(t('The field %field has been updated to use %multiple values, to match the multiple value setting of the Multigroup %group.', array( - '%field' => $field['label'], '%multiple' => $multiple_values[$multiple], '%group' => $groups[$new_group]['label']))); - } + foreach ($fields as $field_name => $field) { + $new_group = $form_values[$field_name]['parent']; + $old_group = $form_values[$field_name]['prev_parent']; + if (!empty($new_group) && isset($groups[$new_group]) && $groups[$new_group]['group_type'] == 'multigroup') { + $allowed_in = content_multigroup_allowed_in($field, $groups[$new_group]); + if (!$allowed_in['allowed']) { + form_set_error($field_name, $allowed_in['message']); } - elseif (!empty($old_group) && isset($groups[$old_group]) && $groups[$old_group]['group_type'] == 'multigroup') { - $allowed_out = content_multigroup_allowed_out($field, $groups[$old_group]); - if (!$allowed_out['allowed']) { - form_set_error($field_name, $allowed_out['message']); - } - elseif (!empty($allowed_out['message'])) { - drupal_set_message($allowed_out['message']); + else { + if (!empty($allowed_in['message'])) { + drupal_set_message($allowed_in['message']); } + module_load_include('inc', 'content', 'includes/content.crud'); + $content_type = content_types($type_name); + $group_multiple = $groups[$new_group]['settings']['multigroup']['multiple']; + $multiple_values = content_multigroup_multiple_values(); + $field = $content_type['fields'][$field_name]; + $field['multiple'] = $group_multiple; + $field = content_field_instance_collapse($field); + content_field_instance_update($field); + drupal_set_message(t('The field %field has been updated to use %multiple values, to match the multiple value setting of the Multigroup %group.', array( + '%field' => $field['label'], '%multiple' => $multiple_values[$group_multiple], '%group' => $groups[$new_group]['label']))); + } + } + elseif (!empty($old_group) && isset($groups[$old_group]) && $groups[$old_group]['group_type'] == 'multigroup') { + $allowed_out = content_multigroup_allowed_out($field, $groups[$old_group]); + if (!$allowed_out['allowed']) { + form_set_error($field_name, $allowed_out['message']); + } + elseif (!empty($allowed_out['message'])) { + drupal_set_message($allowed_out['message']); } } } @@ -230,12 +240,12 @@ function content_multigroup_allowed_in($ // We can't allow fields with more multiple values than the group has // to be moved into it. $max_existing = content_max_delta($field['field_name']); - $group_max = $group['settings']['multigroup']['multiple']; + $group_multiple = $group['settings']['multigroup']['multiple']; $multiple_values = content_multigroup_multiple_values(); - if ($group_max != 1 && $max_existing > $group_max) { + if ($group_multiple != 1 && $max_existing > $group_multiple) { return array( 'allowed' => FALSE, - 'message' => t('This change is not allowed. The field %field already has %multiple values in the database but the group %group only allows %group_max. Making this change would result in the loss of data.', array('%field' => $field['widget']['label'], '%multiple' => $max_existing, '%group' => $group['label'], '%group_max' => $multiple_values[$group_max])) + 'message' => t('This change is not allowed. The field %field already has %multiple values in the database but the group %group only allows %group_max. Making this change would result in the loss of data.', array('%field' => $field['widget']['label'], '%multiple' => $max_existing, '%group' => $group['label'], '%group_max' => $multiple_values[$group_multiple])) ); } @@ -254,7 +264,7 @@ function content_multigroup_allowed_in($ 'nodereference_select', 'userreference_buttons', 'userreference_select', - ); + ); $allowed_widgets = array_merge($allowed_widgets, module_invoke_all('content_multigroup_allowed_widgets')); if (!in_array($field['widget']['type'], $allowed_widgets)) { return array( @@ -295,14 +305,14 @@ function content_multigroup_allowed_out( $max_existing = content_max_delta($field['field_name']); $no_remove_widgets = array( - 'optionwidgets_select', - 'optionwidgets_buttons', - 'optionwidgets_onoff', - 'nodereference_buttons', - 'nodereference_select', - 'userreference_buttons', - 'userreference_select', - ); + 'optionwidgets_select', + 'optionwidgets_buttons', + 'optionwidgets_onoff', + 'nodereference_buttons', + 'nodereference_select', + 'userreference_buttons', + 'userreference_select', + ); $no_remove_widgets = array_merge($no_remove_widgets, module_invoke_all('content_multigroup_no_remove_widgets')); if (in_array($field['widget']['type'], $no_remove_widgets) && $max_existing > 0) { return array( @@ -336,14 +346,17 @@ function content_multigroup_display_over $contexts_selector = $form['#contexts']; // Gather type information. - $type = content_types($type_name); - $field_types = _content_field_types(); - $fields = $type['fields']; + $content_type = content_types($type_name); + + // The content module stops building the form if the type has no fields. + if (empty($content_type['fields'])) { + return; + } $groups = $group_options = array(); if (module_exists('fieldgroup')) { - $groups = fieldgroup_groups($type['type']); - $group_options = _fieldgroup_groups_label($type['type']); + $groups = fieldgroup_groups($type_name); + $group_options = _fieldgroup_groups_label($type_name); } $contexts = content_build_modes($contexts_selector); @@ -353,41 +366,41 @@ function content_multigroup_display_over 'hidden' => t(''), ); $options = array( - 'none' => t('none'), + 'simple' => t('Simple'), 'fieldset' => t('Fieldset'), 'hr' => t('Horizontal line'), //'table' => t('Table'), // TODO add this later - 'hidden' => t(''), ); - foreach ($groups as $name => $group) { + foreach ($groups as $group_name => $group) { if ($group['group_type'] != 'multigroup') { continue; } - $defaults = $group['settings']['multigroup']['display_settings']; + $subgroup_settings = isset($group['settings']['multigroup']['subgroup']) ? $group['settings']['multigroup']['subgroup'] : array(); - $form_name = $name .'_subgroup'; - $form['#fields'] = array_merge(array($form_name), $form['#fields']); - $form[$form_name] = array( + $subgroup_name = $group_name .'_subgroup'; + $form['#fields'] = array_merge(array($subgroup_name), $form['#fields']); + $form[$subgroup_name] = array( 'human_name' => array('#value' => t('[Subgroup format]')), 'weight' => array('#type' => 'value', '#value' => -20), - 'parent' => array('#type' => 'value', '#value' => $name), + 'parent' => array('#type' => 'value', '#value' => $group_name), + 'subgroup' => array('#type' => 'value', '#value' => 1), ); if ($contexts_selector == 'basic') { - $form[$form_name]['label'] = array( + $form[$subgroup_name]['label'] = array( '#type' => 'select', '#options' => $label_options, - '#default_value' => isset($defaults['label']) ? $defaults['label'] : 'above', + '#default_value' => isset($subgroup_settings['label']) ? $subgroup_settings['label'] : 'above', ); } foreach ($contexts as $key => $title) { - $form[$form_name][$key]['format'] = array( + $form[$subgroup_name][$key]['format'] = array( '#type' => 'select', '#options' => $options, - '#default_value' => isset($defaults[$key]) ? $defaults[$key] : 'fieldset', + '#default_value' => isset($subgroup_settings[$key]['format']) ? $subgroup_settings[$key]['format'] : 'fieldset', ); + $form[$subgroup_name][$key]['exclude'] = array('#type' => 'value', '#value' => 0); } } - return $form; } /** @@ -397,19 +410,18 @@ function content_multigroup_display_over * tries to use our 'field'. */ function content_multigroup_display_overview_form_submit($form, &$form_state) { - $form_values = $form_state['values']; - // Find any groups we inserted into the display fields form, // save our settings, and remove them from $form_state. - foreach ($form_values as $key => $values) { - if (in_array($key, $form['#fields']) && substr($key, -9) == '_subgroup') { - $group_name = str_replace('_subgroup', '', $key); + foreach ($form_state['values'] as $key => $values) { + if (in_array($key, $form['#fields']) && !empty($values['parent']) && !empty($values['subgroup'])) { + $group_name = $values['parent']; $groups = fieldgroup_groups($form['#type_name']); $group = $groups[$group_name]; + unset($values['subgroup'], $values['parent']); // We have some numeric keys here, so we can't use array_merge. foreach ($values as $k => $v) { - $group['settings']['multigroup']['display_settings'][$k] = $v; + $group['settings']['multigroup']['subgroup'][$k] = $v; } fieldgroup_save_group($form['#type_name'], $group); @@ -430,7 +442,7 @@ function content_multigroup_group_edit_f $group_name = $form['group_name']['#default_value']; $content_type = content_types($type_name); - $groups = fieldgroup_groups($content_type['type']); + $groups = fieldgroup_groups($type_name); $group = $groups[$group_name]; if ($group['group_type'] != 'multigroup') { @@ -442,7 +454,7 @@ function content_multigroup_group_edit_f $form['group_type'] = array( '#type' => 'hidden', '#value' => $group['group_type'], - ); + ); $form['settings']['multigroup'] = array( '#type' => 'fieldset', '#title' => t('Other settings'), @@ -454,13 +466,13 @@ function content_multigroup_group_edit_f $description .= t("'Unlimited' will provide an 'Add more' button so the users can add repeat it as many times as they like.") . ' '; $description .= t('All fields in this group will automatically be set to allow this number of values.'); - $multiple = isset($group['settings']['multigroup']['multiple']) ? $group['settings']['multigroup']['multiple'] : 1; + $group_multiple = isset($group['settings']['multigroup']['multiple']) ? $group['settings']['multigroup']['multiple'] : 1; $form['settings']['multigroup']['multiple'] = array( '#tree' => TRUE, '#type' => 'select', '#title' => t('Number of repeats'), '#options' => content_multigroup_multiple_values(), - '#default_value' => $multiple, + '#default_value' => $group_multiple, '#description' => $description, ); @@ -469,8 +481,8 @@ function content_multigroup_group_edit_f '#title' => t('Labels'), '#description' => t("Labels for each subgroup of fields. Labels can be hidden or shown in various contexts using the 'Display fields' screen."), ); - if ($multiple < 2) { - $multiple = 0; + if ($group_multiple < 2) { + $group_multiple = 0; } for ($i = 0; $i < 10; $i++) { $form['settings']['multigroup']['labels'][$i] = array( @@ -482,7 +494,6 @@ function content_multigroup_group_edit_f $form['#validate'][] = 'content_multigroup_group_edit_form_validate'; $form['#submit'][] = 'content_multigroup_group_edit_form_submit'; - return $form; } /** @@ -523,10 +534,9 @@ function content_multigroup_group_edit_f $content_type = $form['#content_type']; $groups = fieldgroup_groups($content_type['type']); $group = $groups[$form_values['group_name']]; - $multiple = $form_values['settings']['multigroup']['multiple']; - foreach ($group['fields'] as $field_name => $data) { - $field = $content_type['fields'][$field_name]; - $field['multiple'] = $multiple; + $group_fields = array_intersect_key($content_type['fields'], $group['fields']); + foreach ($group_fields as $field_name => $field) { + $field['multiple'] = $form_values['settings']['multigroup']['multiple']; $field = content_field_instance_collapse($field); content_field_instance_update($field); } @@ -541,65 +551,98 @@ function content_multigroup_group_edit_f * d-n-d each collection of fields as a single delta item. */ function content_multigroup_fieldgroup_form(&$form, &$form_state, $form_id, $group) { - if ($group['group_type'] != 'multigroup' || - !empty($form[$group['group_name']]['#access']) || empty($form[$group['group_name']])) { + $group_name = $group['group_name']; + if ($group['group_type'] != 'multigroup' || !empty($form[$group_name]['#access']) || empty($form[$group_name])) { return; } $node = $form['#node']; - $fields = $group['fields']; - $content_fields = content_fields(); - $group_name = $group['group_name']; - - // Use the first field in the group to get the item counts. - $first_field_name = array_shift(array_keys($group['fields'])); - $first_field = isset($content_fields[$first_field_name]) ? $content_fields[$first_field_name] : array(); - $first_field_items = isset($node->$first_field_name) ? $node->$first_field_name : array(); + $content_type = content_types($group['type_name']); + $group_fields = array_intersect_key($content_type['fields'], $group['fields']); + $group_multiple = $group['settings']['multigroup']['multiple']; - $group['multiple'] = $group['settings']['multigroup']['multiple']; - switch ($group['multiple']) { + switch ($group_multiple) { case 0: - $max = 0; + $group_deltas = array(0); + $max_delta = 0; break; + case 1: - // Is this a new node? - if (empty($first_field_items)) { - $max = 1; + // Compute deltas based on the field with the highest number of items. + $group_deltas = array(); + $max_delta = -1; + foreach ($group_fields as $field_name => $field) { + $field_items = isset($node->$field_name) ? $node->$field_name : array(); + if (!empty($field_items)) { + $field = $group_fields[$field_name]; + $field_deltas = array_keys(content_set_empty($field, $field_items)); + $field_max = (!empty($field_deltas) ? max($field_deltas) : 0); + if ($field_max > $max_delta || empty($group_deltas)) { + $max_delta = $field_max; + $group_deltas = $field_deltas; + } + } + } + $current_item_count = (isset($form_state['item_count'][$group_name]) ? $form_state['item_count'][$group_name] : count($group_deltas)); + if ($current_item_count > 0) { + // We always want at least one empty item for the user to fill in. + $current_item_count++; } else { - $filled_items = content_set_empty($first_field, $first_field_items); - $current_item_count = isset($form_state['item_count'][$group_name]) - ? $form_state['item_count'][$group_name] - : count($first_field_items); - // We always want at least one empty icon for the user to fill in. - $max = ($current_item_count > count($filled_items)) - ? $current_item_count - 1 - : count($filled_items); + // Default number of empty items when none is present. + $current_item_count = 1; + } + while (count($group_deltas) < $current_item_count) { + $max_delta++; + $group_deltas[] = $max_delta; } break; + default: - $max = $group['multiple'] - 1; + $group_deltas = array_keys(array_fill(0, $group_multiple, 0)); + $max_delta = $group_multiple - 1; break; } $form[$group_name]['#theme'] = 'content_multigroup_node_form'; - $form[$group_name]['#multiple'] = !empty($max); + $form[$group_name]['#item_count'] = count($group_deltas); $form[$group_name]['#type_name'] = $group['type_name']; $form[$group_name]['#group_name'] = $group_name; $form[$group_name]['#group_label'] = $group['label']; - $form[$group_name]['#element_validate'] = array('content_multigroup_node_form_validate'); $form[$group_name]['#tree'] = TRUE; + if (!isset($form['#multigroups'])) { + $form['#multigroups'] = array(); + } + $form['#multigroups'][$group_name] = $group_fields; - for ($delta = 0; $delta <= $max; $delta++) { + // Attach our own after build handler to the form, used to fix posting data + // and the form structure, moving fields back to their original positions. + // That is, move them from group->delta->field back to field->delta. + if (!isset($form['#after_build'])) { + $form['#after_build'] = array(); + } + if (!in_array('content_multigroup_node_form_after_build', $form['#after_build'])) { + array_unshift($form['#after_build'], 'content_multigroup_node_form_after_build'); + } + + // Attach our own validation handler to the form, used to check for empty fields. + if (!isset($form['#validate'])) { + $form['#validate'] = array(); + } + if (!in_array('content_multigroup_node_form_validate', $form['#validate'])) { + array_unshift($form['#validate'], 'content_multigroup_node_form_validate'); + } + + foreach ($group_deltas as $delta) { content_multigroup_group_form($form, $form_state, $group, $delta); } // Unset the original group field values now that we've moved them. - foreach ($fields as $field_name => $field) { + foreach (array_keys($group_fields) as $field_name) { unset($form[$group_name][$field_name]); } - if ($add_more = content_multigroup_add_more($form, $form_state, $group)) { + if (($add_more = content_multigroup_add_more($form, $form_state, $group)) !== FALSE) { $form[$group_name] += $add_more; } } @@ -617,13 +660,14 @@ function content_multigroup_group_form(& module_load_include('inc', 'content', 'includes/content.node_form'); $node = $form['#node']; - $fields = $group['fields']; - $content_fields = content_fields(); + $type_name = $group['type_name']; + $content_type = content_types($type_name); + $group_fields = array_intersect_key($content_type['fields'], $group['fields']); $group_name = $group['group_name']; - $group['multiple'] = $group['settings']['multigroup']['multiple']; - $form[$group_name]['#fields'] = array_keys($group['fields']); + $group_multiple = $group['settings']['multigroup']['multiple']; + $form[$group_name]['#fields'] = array_keys($group_fields); - foreach ($fields as $field_name => $group_field) { + foreach ($group_fields as $field_name => $field) { if (empty($form[$group_name][$delta])) { $form[$group_name] += array($delta => array($field_name => array())); } @@ -631,19 +675,13 @@ function content_multigroup_group_form(& $form[$group_name][$delta][$field_name] = array(); } + $item_count = (isset($form_state['item_count'][$group_name]) ? $form_state['item_count'][$group_name] : $form[$group_name]['#item_count']); $form[$group_name][$delta]['_weight'] = array( '#type' => 'weight', - '#delta' => $delta, // this 'delta' is the 'weight' element's property + '#delta' => $item_count, // this 'delta' is the 'weight' element's property '#default_value' => $delta, '#weight' => 100, ); - $form[$group_name][$delta]['_delta'] = array( - '#type' => 'hidden', - '#value' => $delta, - ); - - - $field = $content_fields[$field_name]; // Make each field into a pseudo single value field // with the right delta value. @@ -668,141 +706,277 @@ function content_multigroup_group_form(& $node_copy->$field_name = array($delta => NULL); } $form['#node'] = $node_copy; - $field_form = content_field_form($form, $form_state, $field, $delta); - // Place the new $field_form into the $delta position in the group form. + // Place the new element into the $delta position in the group form. if (content_handle('widget', 'multiple values', $field) == CONTENT_HANDLE_CORE) { + $field_form = content_field_form($form, $form_state, $field, $delta); $value = array_key_exists($delta, $field_form[$field_name]) ? $delta : 0; $form[$group_name][$delta][$field_name] = $field_form[$field_name][$value]; } else { + // When the form is submitted, get the element data from the form values. + if (isset($form_state['values'][$field_name])) { + $form_state_copy = $form_state; + if (isset($form_state_copy['values'][$field_name][$delta])) { + $form_state_copy['values'][$field_name] = array($delta => $form_state_copy['values'][$field_name][$delta]); + } + else { + $form_state_copy['values'][$field_name] = array($delta => NULL); + } + $field_form = content_field_form($form, $form_state_copy, $field, $delta); + } + else { + $field_form = content_field_form($form, $form_state, $field, $delta); + } + + // Multiple value fields have an additional level in the array form that + // needs to get fixed. + if (!isset($field_form[$field_name]['#element_validate'])) { + $field_form[$field_name]['#element_validate'] = array(); + } + $field_form[$field_name]['#element_validate'][] = 'content_multigroup_fix_multivalue_fields'; + $form[$group_name][$delta][$field_name] = $field_form[$field_name]; } $form[$group_name][$delta][$field_name]['#weight'] = $field['widget']['weight']; - - // Add in our validation step, and make sure it preceeds other - // processing so we can massage the element back to the normal position. - if (empty($form[$group_name][$delta][$field_name]['#element_validate'])) { - $form[$group_name][$delta][$field_name]['#element_validate'] = array(); - } - array_unshift($form[$group_name][$delta][$field_name]['#element_validate'], 'content_multigroup_node_item_validate'); } // Reset the form '#node' back to its original value. $form['#node'] = $node; +} +/** + * Fix form and posting data when the form is submitted. + * + * FormAPI uses form_builder() during form processing to map incoming $_POST + * data to the proper elements in the form. It builds the '#parents' array, + * copies the $_POST array to the '#post' member of all form elements, and it + * also builds the $form_state['values'] array. Then the '#after_build' hook is + * invoked to allow custom processing of the form structure, and that happens + * just before validation and submit handlers are executed. + * + * During hook_form_alter(), the multigroup module altered the form structure + * moving elements from field->delta to multigroup->delta->field position, + * which is what has been processed by FormAPI to build the form structures, + * but field validation (and submit) handlers expect their data to be located + * in their original positions. + * + * We now need to move the fields back to their original positions in the form, + * and we need to do so without altering the form rendering process, which is + * now reflecting the structure the multigroup is interested in. We just need + * to fix the parts of the form that affect validation and submit processing. + */ +function content_multigroup_node_form_after_build($form, &$form_state) { + if ($form_state['submitted']) { + // Fix value positions in $form_state for the fields in multigroups. + foreach (array_keys($form['#multigroups']) as $group_name) { + content_multigroup_node_form_fix_values($form, $form_state, $form['#node']->type, $group_name); + } + + // Fix form element parents for all fields in multigroups. + content_multigroup_node_form_fix_parents($form, $form['#multigroups']); + + // Update posting data to reflect delta changes in the form structure. + if (!empty($_POST)) { + content_multigroup_node_form_fix_post($form); + } + } return $form; } /** - * Swap transposed field/delta values back - * to their normal positions in the node. + * Node form validation handler. + * + * If all fields in a delta subgroup are empty, then we can let the + * content module remove them. See content_set_empty(). */ -function content_multigroup_node_item_validate($element, &$form_state) { - static $weights = array(); +function content_multigroup_node_form_validate($form, &$form_state) { + $type_name = $form['#node']->type; + $content_type = content_types($type_name); + $groups = fieldgroup_groups($type_name); - //dsm($form_state['values']); - $form_values = $form_state['values']; - $field_name = array_pop($element['#parents']); - $delta = array_pop($element['#parents']); - $group_name = array_pop($element['#parents']); - - // Identify the new delta value for each field. - - // Find the original delta values for this group, save as static value - // because the group will acquire and lose values while we process it. - if (!array_key_exists($group_name, $weights)) { - $items = $form_state['values'][$group_name]; - $weights[$group_name] = array(); - foreach ($items as $count => $value) { - // Allow for the possibility of matching _weights and missing deltas. - $weight = floatval($value['_weight']); - $old_delta = intval($value['_delta']); - if (empty($weights[$group_name][$weight]) || !in_array($old_delta, $weights[$group_name][$weight])) { - $weights[$group_name][$weight][] = $old_delta; - } - } - ksort($weights[$group_name]); - } - $count = 0; - foreach ($weights[$group_name] as $weight => $values) { - foreach ($values as $old_delta) { - if ($old_delta === $delta) { - $delta = $count; - //dsm('moving delta values: '.$group_name.'>'.$field_name.'>'.'from '. $old_delta .' to '. $delta); - break 2; - } - $count++; - } - } - // We figured out what the new order for the fields is, - // so set the value for the new delta. - - // We move these new values back up to the top level of the - // node and out of the group so the Content module will find and - // save the new values and so they don't get mixed into the - // remaining, unaltered, values in the group. - array_push($element['#parents'], $field_name); - array_push($element['#parents'], $delta); - - // It's very important to use $form_values instead of $element['#value'] - // here, because $element['#value'] is sometimes missing changes - // made in #element_validate processing done by other modules. - $value = isset($form_values[$group_name][$delta][$field_name]) ? $form_values[$group_name][$delta][$field_name] : NULL; - - // Fields that use optionwidgets have an extra array level in the value - // because of the optionwidgets transposition that forces a delta value - // into the result array. This works fine when a delta value is between - // the field name and the field value, as in normal nodes, but not when - // we reverse the field and the delta, so in this case we need to - // promote the nested delta value back up to the field level. - if (is_array($value) && content_multigroup_uses_optionwidgets($field_name, $element['#type_name'])) { - $value = array_shift($value); + foreach ($form['#multigroups'] as $group_name => $group_fields) { + $empty_deltas = array(); + foreach ($group_fields as $field_name => $field) { + $is_empty_function = $field['module'] .'_content_is_empty'; + foreach ($form_state['values'][$field_name] as $delta => $item) { + if (!isset($empty_deltas[$delta])) { + $empty_deltas[$delta] = TRUE; + } + if (!$is_empty_function($item, $field)) { + $empty_deltas[$delta] = FALSE; + } + } + } + + foreach ($empty_deltas as $delta => $is_empty) { + foreach ($group_fields as $field_name => $field) { + $form_state['values'][$field_name][$delta]['_keep_empty'] = $is_empty ? 0 : 1; + } + } } +} - //dsm('setting value of '. $field_name.'>'.$delta); - //dsm($value); - form_set_value($element, $value, $form_state); +/** + * Fix value positions in $form_state for the fields in a multigroup. + */ +function content_multigroup_node_form_fix_values(&$form, &$form_state, $type_name, $group_name) { + $content_type = content_types($type_name); + $groups = fieldgroup_groups($type_name); + $group = $groups[$group_name]; + $group_fields = array_intersect_key($content_type['fields'], $group['fields']); + + // Move group data from group->delta->field to field->delta. + $group_data = array(); + foreach ($form_state['values'][$group_name] as $delta => $items) { + // Skip 'add more' button. + if (!is_array($items) || !isset($items['_weight'])) { + continue; + } + foreach ($group_fields as $field_name => $field) { + if (!isset($group_data[$field_name])) { + $group_data[$field_name] = array(); + } + // Get the field weight from the group and keep track of the current + // delta for each field item. + $group_data[$field_name][$delta] = array_merge($items[$field_name], array( + '_weight' => $items['_weight'], + '_old_delta' => $delta, + )); + } + } + + $form_group_sorted = FALSE; + foreach ($group_data as $field_name => $items) { + + // Sort field items according to drag-n-drop reordering. Deltas are also + // rebuilt to start counting from 0 to n. Note that since all fields in the + // group share the same weight, their deltas remain in sync. + usort($items, '_content_sort_items_helper'); + + // Now we need to apply the same ordering to the form elements. Also, + // note that deltas have changed during the sort operation, so we need + // to reflect this delta conversion in the form. + if (!$form_group_sorted) { + $form_group_items = array(); + $form_deltas = array(); + foreach ($items as $new_delta => $item) { + $form_deltas[$item['_old_delta']] = $new_delta; + $form_group_items[$new_delta] = $form[$group_name][$item['_old_delta']]; + unset($form[$group_name][$item['_old_delta']]); + } + foreach ($form_group_items as $new_delta => $form_group_item) { + $form[$group_name][$new_delta] = $form_group_item; + } + content_multigroup_node_form_fix_deltas($form[$group_name], $form_deltas); + $form_group_sorted = TRUE; + } + + // Get rid of the old delta value. + foreach (array_keys($items) as $delta) { + unset($items[$delta]['_old_delta']); + } + + // Fix field and delta positions in the $_POST array. + if (!empty($_POST)) { + $_POST[$field_name] = array(); + foreach ($items as $new_delta => $item) { + $_POST[$field_name][$new_delta] = $item; + } + if (isset($_POST[$group_name])) { + unset($_POST[$group_name]); + } + } + + // Move field items back to their original positions. + $form_state['values'][$field_name] = $items; + } + + // Finally, get rid of the group data in form values. + unset($form_state['values'][$group_name]); } /** - * Helper function for identifying fields that use - * optionwidgets transpositions. + * Fix deltas for all affected form elements. */ -function content_multigroup_uses_optionwidgets($field_name, $type_name) { - static $optionwidgets; - if (empty($optionwidgets)) { - $optionwidgets = array( - 'optionwidgets_select', - 'optionwidgets_buttons', - 'optionwidgets_onoff', - 'nodereference_buttons', - 'nodereference_select', - 'userreference_buttons', - 'userreference_select', - ); - // Add hook where other widgets that use optionwidgets can announce it. - $optionwidgets = array_merge($optionwidgets, module_invoke_all('content_multigroup_uses_optionwidgets')); +function content_multigroup_node_form_fix_deltas(&$elements, $form_deltas) { + foreach (element_children($elements) as $key) { + if (isset($elements[$key]) && $elements[$key]) { + + // Fix the second item, the delta value, of the element's '#parents' array. + $elements[$key]['#parents'][1] = $form_deltas[$elements[$key]['#parents'][1]]; + + // If present, fix delta value in '#delta' attribute of the element. + if (isset($elements[$key]['#delta']) && isset($form_deltas[$elements[$key]['#delta']])) { + $elements[$key]['#delta'] = $form_deltas[$elements[$key]['#delta']]; + } + + // Recurse through all children elements. + content_multigroup_node_form_fix_deltas($elements[$key], $form_deltas); + } } +} - $types = content_types($type_name); - $fields = $types['fields']; - $field = $fields[$field_name]; - if (in_array($field['widget']['type'], $optionwidgets)) { - return TRUE; +/** + * Fix form element parents for all fields in multigroups. + * + * The $element['#parents'] array needs to reflect the position of the fields + * in the $form_state['values'] array so that form_set_value() can be safely + * used by field validation handlers. + */ +function content_multigroup_node_form_fix_parents(&$elements, $multigroups) { + foreach (element_children($elements) as $key) { + if (isset($elements[$key]) && $elements[$key]) { + + // Check if the current element is child of a multigroup. The #parents + // array for field values has, at least, 3 parent elements, being the + // first one the name of a multigroup. + if (count($elements[$key]['#parents']) >= 3 && isset($multigroups[$elements[$key]['#parents'][0]])) { + + // Extract group name, delta and field name from the #parents array. + array_shift($elements[$key]['#parents']); + $delta = array_shift($elements[$key]['#parents']); + $field_name = array_shift($elements[$key]['#parents']); + + // Now, insert field name and delta to the #parents array. + array_unshift($elements[$key]['#parents'], $field_name, $delta); + } + + // Recurse through all children elements. + content_multigroup_node_form_fix_parents($elements[$key], $multigroups); + } + } +} + +/** + * Update posting data to reflect delta changes in the form structure. + * + * The $_POST array is fixed in content_multigroup_node_form_fix_values(). + */ +function content_multigroup_node_form_fix_post(&$elements) { + foreach (element_children($elements) as $key) { + if (isset($elements[$key]) && $elements[$key]) { + + // Update the element copy of the $_POST array. + $elements[$key]['#post'] = $_POST; + + // Recurse through all children elements. + content_multigroup_node_form_fix_post($elements[$key]); + } } - return FALSE; + + // Update the form copy of the $_POST array. + $elements['#post'] = $_POST; } /** - * Validation for the whole node group. + * Fix the value for fields that deal with multiple values themselves. */ -function content_multigroup_node_form_validate($element, $form_state) { - // We moved all the new field values out of the field group - // and up to the top level of the node, now get rid of the - // original group values. - form_set_value($element, NULL, $form_state); - return; +function content_multigroup_fix_multivalue_fields($element, &$form_state) { + $field_name = $element['#field_name']; + $delta = $element['#delta']; + $value = $form_state['values'][$field_name][$delta][0]; + form_set_value($element, $value, $form_state); } /** @@ -815,69 +989,79 @@ function content_multigroup_fieldgroup_v $group_name = $group['group_name']; $node_copy = drupal_clone($node); - $max = $group['settings']['multigroup']['multiple']; - $count = 0; - foreach ($group['fields'] as $field_name => $field) { - $count = max($count, count($node->$field_name)); - } + $group_multiple = $group['settings']['multigroup']['multiple']; + $subgroup_settings = isset($group['settings']['multigroup']['subgroup']) ? $group['settings']['multigroup']['subgroup'] : array(); + $show_label = isset($subgroup_settings['label']) ? $subgroup_settings['label'] : 'above'; + $subgroup_labels = isset($group['settings']['multigroup']['labels']) ? $group['settings']['multigroup']['labels'] : array(); + $subgroup_format = isset($subgroup_settings[$context]['format']) ? $subgroup_settings[$context]['format'] : 'fieldset'; + $group_field_names = array_keys($group['fields']); - $group['multiple'] = isset($group['settings']['multigroup']['multiple']) ? $group['settings']['multigroup']['multiple'] : 1; - $labels = isset($group['settings']['multigroup']['labels']) ? $group['settings']['multigroup']['labels'] : array(); - $format = isset($group['settings']['multigroup']['display_settings'][$context]['format']) ? $group['settings']['multigroup']['display_settings'][$context]['format'] : 'fieldset'; - $show_label = isset($group['settings']['multigroup']['display_settings']['label']) ? $group['settings']['multigroup']['display_settings']['label'] : 'above'; - - switch ($group['multiple']) { + switch ($group_multiple) { case 0: - $max = 0; + $group_deltas = array(0); break; + case 1: - $max = $count; + // Compute deltas based on the field with the highest number of items. + $group_deltas = array(); + $max_delta = -1; + foreach ($group_field_names as $field_name) { + $field_deltas = is_array($node->content[$field_name]['field']['items']) ? array_keys($node->content[$field_name]['field']['items']) : array(); + $field_max = (!empty($field_deltas) ? max($field_deltas) : 0); + if ($field_max > $max_delta) { + $max_delta = $field_max; + $group_deltas = $field_deltas; + } + } break; + default: - $max = $group['multiple']; + $group_deltas = array_keys(array_fill(0, $group_multiple - 1, 0)); break; } - for ($delta = 0; $delta < $max; $delta++) { - $element[$delta] = array('#weight' => $delta); - - $label = !empty($labels[$delta]) && $show_label == 'above' ? $labels[$delta] : ''; - - foreach ($group['fields'] as $field_name => $field) { + foreach ($group_deltas as $i => $delta) { + $element[$delta] = array( + '#title' => ($show_label == 'above' && !empty($subgroup_labels[$i]) ? check_plain(t($subgroup_labels[$i])) : ''), + '#attributes' => array('class' => 'multigroup multigroup-'. $i), + '#weight' => $delta, + ); - // Create a pseudo node that only has the value we want - // in this group and pass it to the formatter. + // Create a pseudo node that only has the value we want in this group and + // pass it to the formatter. + // Default implementation of content-field.tpl.php uses a different CSS + // class for inline labels when delta is zero, but this is not needed in + // the context of multigroup, so we place the field into index 1 of the + // item list. Note that CSS class "field-label-inline" is overridden in the + // multigroup stylesheet because here labels should always be visible. + foreach ($group_field_names as $field_name) { if (isset($node->content[$field_name])) { $node_copy->content[$field_name]['field']['items'] = array( - $delta => isset($node->content[$field_name]['field']['items'][$delta]) ? $node->content[$field_name]['field']['items'][$delta] : NULL, - ); + 1 => isset($node->content[$field_name]['field']['items'][$delta]) ? $node->content[$field_name]['field']['items'][$delta] : NULL, + ); $element[$delta][$field_name] = $node_copy->content[$field_name]; $element[$delta][$field_name]['#delta'] = $delta; } } - switch ($format) { - case 'table': - $element[$delta]['#theme'] = 'content_multigroup_display_table'; - $element[$delta]['#title'] = $label; + + switch ($subgroup_format) { + case 'simple': + $element[$delta]['#theme'] = 'content_multigroup_display_simple'; break; case 'fieldset': - $element[$delta]['#type'] = 'fieldset'; - $element[$delta]['#title'] = $label; + $element[$delta]['#type'] = 'content_multigroup_display_fieldset'; break; case 'hr': $element[$delta]['#theme'] = 'content_multigroup_display_hr'; - $element[$delta]['#title'] = $label; break; - default: - $element[$delta]['#theme'] = 'content_multigroup_display_simple'; - $element[$delta]['#title'] = $label; + case 'table': + $element[$delta]['#theme'] = 'content_multigroup_display_table'; break; } - } - foreach ($group['fields'] as $field_name => $field) { + foreach ($group_field_names as $field_name) { if (isset($element[$field_name])) { unset($element[$field_name]); } @@ -890,10 +1074,18 @@ function content_multigroup_fieldgroup_v * Combine multiple values into a table with drag-n-drop reordering. */ function theme_content_multigroup_node_form($element) { + $groups = fieldgroup_groups($element['#type_name']); + $group_name = $element['#group_name']; + $group = $groups[$group_name]; + $group_multiple = $group['settings']['multigroup']['multiple']; $output = ''; - if ($element['#multiple'] >= 1) { + + if ($group_multiple >= 1) { $table_id = $element['#group_name'] .'_values'; $order_class = $element['#group_name'] .'-delta-order'; + $subgroup_settings = isset($group['settings']['multigroup']['subgroup']) ? $group['settings']['multigroup']['subgroup'] : array(); + $show_label = isset($subgroup_settings['label']) ? $subgroup_settings['label'] : 'above'; + $subgroup_labels = isset($group['settings']['multigroup']['labels']) ? $group['settings']['multigroup']['labels'] : array(); $header = array( array( @@ -903,15 +1095,11 @@ function theme_content_multigroup_node_f t('Order'), ); $rows = array(); - $groups = fieldgroup_groups($element['#type_name']); - $group = $groups[$element['#group_name']]; - $labels = isset($group['settings']['multigroup']['labels']) ? $group['settings']['multigroup']['labels'] : array(); - $multiple = isset($group['settings']['multigroup']['multiple']) ? $group['settings']['multigroup']['multiple'] : 1; $i = 0; foreach (element_children($element) as $delta => $key) { - if ($key !== $element['#group_name'] .'_add_more') { - $label = !empty($labels[$i]) ? theme('content_multigroup_node_label', $labels[$i]) : ''; + if ($key !== $group_name .'_add_more') { + $label = ($show_label == 'above' && !empty($subgroup_labels[$i]) ? theme('content_multigroup_node_label', check_plain(t($subgroup_labels[$i]))) : ''); $element[$key]['_weight']['#attributes']['class'] = $order_class; $delta_element = drupal_render($element[$key]['_weight']); $cells = array( @@ -921,10 +1109,6 @@ function theme_content_multigroup_node_f ); $rows[] = array( 'data' => $cells, - // TODO Tablesort drag n drop is not working with complex - // field validation. The fields appear to work correctly, - // but element validation seems to get missed or confused - // causing validation errors. Need to investigate why. 'class' => 'draggable', ); } @@ -933,7 +1117,7 @@ function theme_content_multigroup_node_f $output .= theme('table', $header, $rows, array('id' => $table_id, 'class' => 'content-multiple-table')); $output .= $element['#description'] ? '
'. $element['#description'] .'
' : ''; - $output .= drupal_render($element[$element['#group_name'] .'_add_more']); + $output .= drupal_render($element[$group_name .'_add_more']); drupal_add_tabledrag($table_id, 'order', 'sibling', $order_class); } @@ -946,47 +1130,46 @@ function theme_content_multigroup_node_f return $output; } +/** + * Add AHAH add more button, if not working with a programmed form. + */ function content_multigroup_add_more(&$form, &$form_state, $group) { - // Add AHAH add more button, if not working with a programmed form. - $multiple = $group['settings']['multigroup']['multiple']; - $form_element = array(); - if ($multiple != 1 || !empty($form['#programmed'])) { - return $form_element; + $group_multiple = $group['settings']['multigroup']['multiple']; + if ($group_multiple != 1 || !empty($form['#programmed'])) { + return FALSE; } - else { - // Make sure the form is cached so ahah can work. - $form['#cache'] = TRUE; - $content_type = content_types($group['type_name']); - $group_name = $group['group_name']; - $group_name_css = str_replace('_', '-', $group_name); - - $form_element[$group_name .'_add_more'] = array( - '#type' => 'submit', - '#name' => $group_name .'_add_more', - '#value' => t('Add more values'), - '#weight' => $multiple + 1, - // Submit callback for disabled JavaScript. drupal_get_form() might get - // the form from the cache, so we can't rely on content_form_alter() - // including this file. Therefore, call a proxy function to do this. - '#submit' => array('content_multigroup_add_more_submit_proxy'), - '#ahah' => array( - 'path' => 'content_multigroup/js_add_more/'. $content_type['url_str'] .'/'. $group_name, - 'wrapper' => $group_name_css .'-items', - 'method' => 'replace', - 'effect' => 'fade', - ), - // When JS is disabled, the content_add_more_submit handler will find - // the relevant field using these entries. - '#group_name' => $group_name, - '#type_name' => $group['type_name'], - ); - // Add wrappers for the group and 'more' button. - // TODO: could be simplified ? - $form_element['#prefix'] = '
'; - $form_element[$group_name .'_add_more']['#prefix'] = '
'; - $form_element[$group_name .'_add_more']['#suffix'] = '
'; - } + // Make sure the form is cached so ahah can work. + $form['#cache'] = TRUE; + $content_type = content_types($group['type_name']); + $group_name = $group['group_name']; + $group_name_css = str_replace('_', '-', $group_name); + + $form_element = array(); + $form_element[$group_name .'_add_more'] = array( + '#type' => 'submit', + '#name' => $group_name .'_add_more', + '#value' => t('Add more values'), + '#weight' => $group_multiple + 1, + '#submit' => array('content_multigroup_add_more_submit'), + '#ahah' => array( + 'path' => 'content_multigroup/js_add_more/'. $content_type['url_str'] .'/'. $group_name, + 'wrapper' => $group_name_css .'-items', + 'method' => 'replace', + 'effect' => 'fade', + ), + // When JS is disabled, the content_multigroup_add_more_submit handler will + // find the relevant field using these entries. + '#group_name' => $group_name, + '#type_name' => $group['type_name'], + ); + + // Add wrappers for the group and 'more' button. + // TODO: could be simplified ? + $form_element['#prefix'] = '
'; + $form_element[$group_name .'_add_more']['#prefix'] = '
'; + $form_element[$group_name .'_add_more']['#suffix'] = '
'; + return $form_element; } @@ -1003,7 +1186,7 @@ function content_multigroup_add_more_sub // Make the changes we want to the form state. if ($form_state['values'][$group_name][$group_name .'_add_more']) { - $form_state['item_count'][$group_name] = count($form_state['values'][$group_name]); + $form_state['item_count'][$group_name] = count($form_state['values'][$group_name]) - 1; } } @@ -1013,12 +1196,11 @@ function content_multigroup_add_more_sub * Adapted from content_add_more_js to work with groups instead of fields. */ function content_multigroup_add_more_js($type_name_url, $group_name) { - $type = content_types($type_name_url); - $groups = fieldgroup_groups($type['type']); + $content_type = content_types($type_name_url); + $groups = fieldgroup_groups($content_type['type']); $group = $groups[$group_name]; - $group['multiple'] = $group['settings']['multigroup']['multiple']; - if (($group['multiple'] != 1) || empty($_POST['form_build_id'])) { + if (($group['settings']['multigroup']['multiple'] != 1) || empty($_POST['form_build_id'])) { // Invalid request. drupal_json(array('data' => '')); exit; @@ -1059,17 +1241,23 @@ function content_multigroup_add_more_js( unset($form_state['values'][$group_name][$group['group_name'] .'_add_more']); foreach ($_POST[$group_name] as $delta => $item) { $form_state['values'][$group_name][$delta]['_weight'] = $item['_weight']; - $form_state['values'][$group_name][$delta]['_delta'] = $item['_delta']; } + $group['multiple'] = $group['settings']['multigroup']['multiple']; $form_state['values'][$group_name] = _content_sort_items($group, $form_state['values'][$group_name]); $_POST[$group_name] = _content_sort_items($group, $_POST[$group_name]); // Build our new form element for the whole group, asking for one more element. - - $form_state['item_count'] = array($group_name => count($_POST[$group_name]) + 1); $delta = max(array_keys($_POST[$group_name])) + 1; + $form_state['item_count'] = array($group_name => count($_POST[$group_name])); content_multigroup_group_form($form, $form_state, $group, $delta); + // Rebuild weight deltas to make sure they all are equally dimensioned. + foreach ($form[$group_name] as $key => $item) { + if (is_numeric($key) && isset($item['_weight']) && is_array($item['_weight'])) { + $form[$group_name][$key]['_weight']['#delta'] = $delta; + } + } + // Save the new definition of the form. $form_state['values'] = array(); form_set_cache($form_build_id, $form, $form_state); @@ -1086,7 +1274,6 @@ function content_multigroup_add_more_js( // Render the new output. $group_form = $form[$group_name]; - // We add a div around the new content to receive the ahah effect. $group_form[$delta]['#prefix'] = '
'. (isset($group_form[$delta]['#prefix']) ? $group_form[$delta]['#prefix'] : ''); $group_form[$delta]['#suffix'] = (isset($group_form[$delta]['#suffix']) ? $group_form[$delta]['#suffix'] : '') .'
'; @@ -1108,43 +1295,79 @@ function content_multigroup_add_more_js( * Theme the sub group label in the node form. */ function theme_content_multigroup_node_label($text) { - if (!empty($text)) { - return '

'. check_plain($text) .'

'; - } + return !empty($text) ? '

'. $text .'

' : ''; } +/** + * Theme a subgroup of fields in 'simple' format. + * + * No output is generated if all fields are empty. + */ function theme_content_multigroup_display_simple($element) { - $label = ''; - if (!empty($element['#title'])) { - $label .= ''; - } - $output = $label; + $children = $output = ''; foreach (element_children($element) as $key) { - $output .= drupal_render($element[$key]); + $children .= drupal_render($element[$key]); + } + if (!empty($children)) { + $output .= ''; + if (!empty($element['#title'])) { + $output .= ''; + } + $output .= $children .''; } return $output; } -function theme_content_multigroup_display_hr($element) { - $label = ''; - if (!empty($element['#title'])) { - $label .= ''; +/** + * Theme a subgroup of fields in 'fieldset' format. + * + * No output is generated if all fields are empty. + */ +function theme_content_multigroup_display_fieldset($element) { + if (empty($element['#children']) && empty($element['#value'])) { + return ''; } - $output = '
'. $label; + return theme('fieldset', $element); +} + +/** + * Theme a subgroup of fields in 'hr' format. + * + * No output is generated if all fields are empty. + */ +function theme_content_multigroup_display_hr($element) { + $children = $output = ''; foreach (element_children($element) as $key) { - $output .= drupal_render($element[$key]); + $children .= drupal_render($element[$key]); + } + if (!empty($children)) { + $output .= '
'; + if (!empty($element['#title'])) { + $output .= ''; + } + $output .= $children .''; } return $output; } +/** + * Theme a subgroup of fields in 'table' format. + * + * No output is generated if all fields are empty. + * + * @TODO: It is still a copy of 'simple' format. + */ function theme_content_multigroup_display_table($element) { - $label = ''; - if (!empty($element['#title'])) { - $label .= ''; - } - $output = $label; + $children = $output = ''; foreach (element_children($element) as $key) { - $output .= drupal_render($element[$key]); + $children .= drupal_render($element[$key]); + } + if (!empty($children)) { + $output .= ''; + if (!empty($element['#title'])) { + $output .= ''; + } + $output .= $children .''; } return $output; -} \ No newline at end of file +}