See: http://drupal.org/node/650008 This version works with the latest nested fieldgroup cck code added upstream that replaces the old nested fieldgroups cck patch, see: http://drupal.org/node/849420#comment-4011484 This version hasthe suggested change from http://drupal.org/node/650008#comment-4823534 applied. diff -Nurp ../conditional_fields.orig/conditional_fields.module ./conditional_fields.module --- ../conditional_fields.orig/conditional_fields.module 2011-09-14 07:56:10.000000000 -0500 +++ ./conditional_fields.module 2011-09-14 08:04:39.000000000 -0500 @@ -201,6 +201,9 @@ function conditional_fields_nodeapi(&$no return; } + // Get all groups from form + $groups = fieldgroup_groups($node->type); + foreach ($data as $field) { // We might have to look for the field in a group @@ -212,8 +215,12 @@ function conditional_fields_nodeapi(&$no continue; } + // Get group array of the form + $controlled_group_ref = conditional_fields_get_item_group($groups, $controlled_group, $node->content); + $controlling_group_ref = conditional_fields_get_item_group($groups, $controlling_group, $node->content); + // The controlled field is in a group and is not the form for other reasons. Skip. - if ($controlled_group && !$node->content[$controlled_group]['group'][$field['field_name']]) { + if ($controlled_group && !$controlled_group_ref[$field['field_name']]) { continue; } @@ -225,9 +232,9 @@ function conditional_fields_nodeapi(&$no $field_key = array_keys($type['fields'][$field['control_field_name']]['columns']); foreach ((array)$node->$field['control_field_name'] as $value) { $current_values[$field['control_field_name']][] = $value[$field_key[0]]; - if (!empty($value[$field_key[0]])) { + if ($value[$field_key[0]] != "") { if ($node->content[$field['control_field_name']]['field']['#access'] == TRUE || - ($controlling_group && $node->content[$controlling_group]['group'][$field['control_field_name']]['field']['#access'] == TRUE)) { + ($controlling_group && $controlling_group_ref[$field['control_field_name']]['field']['#access'] == TRUE)) { $viewed = TRUE; } } @@ -237,10 +244,10 @@ function conditional_fields_nodeapi(&$no // Hide the controlled field if it is not triggered if (!conditional_fields_is_triggered($current_values[$field['control_field_name']], $field['trigger_values'])) { if ($controlled_group) { - $node->content[$controlled_group]['group'][$field['field_name']]['#access'] = FALSE; + conditional_fields_hide_field_node_viewing($groups, $controlled_group, $node->content, $field['field_name']); } else { - $node->content[$field['field_name']]['#access'] = FALSE; + $node->content[$field['field_name']]['field']['#access'] = FALSE; } } } @@ -296,14 +303,30 @@ function conditional_fields_form_alter(& break; case 'content_add_more_js': // Handle ahah multiple fields - foreach ($form as $item_name => $item) { - if (db_result(db_query("SELECT COUNT(*) FROM {conditional_fields} WHERE field_name = '%s'", $item_name))) { - $form[$item_name]['#post_render'] = array_merge(array('conditional_fields_add_more_post_render'), (array)$form[$item_name]['#post_render']); - foreach (element_children($form[$item_name]) as $element) { - conditional_fields_custom_required_field($form[$item_name][$element]); + + // Find all fieldsets in the form array via a recursive function + // Doing this is better than recursively walking the $form array foreach field in the $data array + $fieldsets = array(); + conditional_fields_node_editing_form_get_fieldgroups($form, $fieldsets); + + $data = conditional_fields_load_data($form['#field']['type']); + + foreach ($data as $row) { + if (in_array($row['field_name'], $fieldsets)){ + $group_name = array_search($row['field_name'], $fieldsets); + $fieldsets[$group_name][$row['field_name']]['#post_render'] = array_merge(array('conditional_fields_add_more_post_render'), (array)$fieldsets[$group_name][$row['field_name']]['#post_render']); + foreach (element_children($fieldsets[$group_name][$row['field_name']]) as $element) { + conditional_fields_custom_required_field($fieldsets[$group_name][$row['field_name']][$element]); + } + } + else { + $form[$row['field_name']]['#post_render'] = array_merge(array('conditional_fields_add_more_post_render'), (array)$form[$row['field_name']]['#post_render']); + foreach (element_children($form[$row['field_name']]) as $element) { + conditional_fields_custom_required_field($form[$row['field_name']][$element]); } } } + break; case 'content_copy_import_form': $form['#submit'][] = 'conditional_fields_import'; @@ -535,7 +558,7 @@ function conditional_fields_fieldgroup_g // Find fields with allowed values which are not inside a group foreach ($form['#content_type']['fields'] as $field) { $in_group = fieldgroup_get_group($form['#content_type']['type'], $field['field_name']); - if (!$in_group) { + if (!$in_group || $in_group == $form['parent']['#default_value']) { if ($allowed_values[$field['field_name']] = conditional_fields_allowed_values($field)) { $available_fields[$field['field_name']] = $field; } @@ -622,6 +645,29 @@ function conditional_fields_allowed_valu } /** + * Return an array of all fieldsets within the $form stored at the first depth of the array + * Each key in this array is a reference to the appropriate $form key + * Therefore all changes to $fieldsets will propogate to the appropriate $form key + * Due to recursion, the results are stored in the $fieldsets parameter + * This will produce a smaller array that can be searched through with less overhead + */ +function conditional_fields_node_editing_form_get_fieldgroups(&$form, &$fieldsets){ + foreach ($form as $form_key => $form_field){ + if (is_array($form[$form_key])){ + if (array_key_exists('#type', $form[$form_key])){ + if (strcasecmp($form[$form_key]['#type'], "fieldset") == 0){ + // The fieldset fields must map to the original form fields + // This allows for modifying the values without having to do a recursive search again + $fieldsets[$form_key] = & $form[$form_key]; + + conditional_fields_node_editing_form_get_fieldgroups($form[$form_key], $fieldsets); + } + } + } + } +} + +/** * Alter node form. We do it in after_build for compatibility * with non-core CCK widgets */ @@ -655,6 +701,11 @@ function conditional_fields_node_after_b $required_fields = array(); $js_settings = array(); + // Find all fieldsets in the form array via a recursive function + // Doing this is better than recursively walking the $form array foreach field in the $data array + $fieldsets = array(); + conditional_fields_node_editing_form_get_fieldgroups($form, $fieldsets); + foreach ($data as $row) { $controlling_fields[$row['control_field_name']][$row['field_name']] = $row['trigger_values']; $controlled_fields[$row['field_name']][$row['control_field_name']] = $row['trigger_values']; @@ -664,16 +715,23 @@ function conditional_fields_node_after_b foreach ($controlling_fields as $controlling_field_name => $controlling_field_descendants) { // Check if the controlling field is in the form, user has access to it, and is editable. $group_of_controlling_field = conditional_fields_get_group($type_name, $controlling_field_name); - $controlling_field = conditional_fields_item_in_form($form, $controlling_field_name, $group_of_controlling_field); + + $controlling_field = conditional_fields_item_in_form($form, $controlling_field_name, $group_of_controlling_field, $fieldsets); if (!$controlling_field || $controlling_field['#access'] === FALSE || $controlling_field['#type'] == 'markup') { $missing_controlling_fields[] = $controlling_field_name; continue; } // Set values on form for themeing. - if ($group_of_controlling_field) { - $form[$group_of_controlling_field][$controlling_field_name]['#controlling_fields'] = TRUE; - conditional_fields_item_apply_theme($form[$group_of_controlling_field][$controlling_field_name]); + if ($group_of_controlling_field != '' && array_key_exists($group_of_controlling_field, $fieldsets)) { + if (is_array($fieldsets[$group_of_controlling_field]['#group_fields'])){ + $fieldsets[$group_of_controlling_field]['#group_fields'][$controlling_field_name]['#controlling_fields'] = TRUE; + conditional_fields_item_apply_theme($fieldsets[$group_of_controlling_field]['#group_fields'][$controlling_field_name]); + } + else { + $fieldsets[$group_of_controlling_field][$controlling_field_name]['#controlling_fields'] = TRUE; + conditional_fields_item_apply_theme($fieldsets[$group_of_controlling_field][$controlling_field_name]); + } } else { $form[$controlling_field_name]['#controlling_fields'] = TRUE; @@ -685,7 +743,7 @@ function conditional_fields_node_after_b foreach ($controlled_fields as $controlled_field_name => $controlled_field_parents) { // Check if the controlled field is in the form and user has access to it. $group_of_controlled_field = conditional_fields_get_group($type_name, $controlled_field_name); - $controlled_field = conditional_fields_item_in_form($form, $controlled_field_name, $group_of_controlled_field); + $controlled_field = conditional_fields_item_in_form($form, $controlled_field_name, $group_of_controlled_field, $fieldsets); if (!$controlled_field || (isset($controlled_field['#access']) && $controlled_field['#access'] === FALSE)) { continue; } @@ -715,8 +773,13 @@ function conditional_fields_node_after_b } case C_FIELDS_ORPHANED_HIDE: // Unset controlled field. - if ($group_of_controlled_field) { - unset($form[$group_of_controlled_field][$controlled_field_name]); + if ($group_of_controlled_field && $group_of_controlled_field != '' && array_key_exists($group_of_controlled_field, $fieldsets)) { + if (is_array($fieldsets[$group_of_controlled_field]['#group_fields'])){ + unset($fieldsets[$group_of_controlled_field]['#group_fields'][$controlled_field_name]); + } + else { + unset($fieldsets[$group_of_controlled_field][$controlled_field_name]); + } } else { unset($form[$controlled_field_name]); @@ -741,18 +804,28 @@ function conditional_fields_node_after_b $required_fields[$group_element] = array('field' => $group_element, 'in_group' => $controlled_field_name); } } + + // wrap groups in controlled field theming + conditional_fields_item_apply_theme($fieldsets[$controlled_field_name], $controlled_field_name); } // Set values on form for themeing. - if ($group_of_controlled_field) { - $form[$group_of_controlled_field][$controlled_field_name]['#controlled_fields'] = TRUE; - conditional_fields_item_apply_theme($form[$group_of_controlled_field][$controlled_field_name]); + if ($group_of_controlled_field && $group_of_controlled_field != '' && array_key_exists($group_of_controlled_field, $fieldsets)) { + if (is_array($fieldsets[$group_of_controlled_field]['#group_fields'])){ + $fieldsets[$group_of_controlled_field]['#group_fields'][$controlled_field_name]['#controlled_fields'] = TRUE; + conditional_fields_item_apply_theme($fieldsets[$group_of_controlled_field]['#group_fields'][$controlled_field_name], ($is_group ? $controlled_field_name : '')); + } + else { + $fieldsets[$group_of_controlled_field][$controlled_field_name]['#controlled_fields'] = TRUE; + conditional_fields_item_apply_theme($fieldsets[$group_of_controlled_field][$controlled_field_name], ($is_group ? $controlled_field_name : '')); + } } else { $form[$controlled_field_name]['#controlled_fields'] = TRUE; - $is_group ? conditional_fields_item_apply_theme($form[$controlled_field_name], $controlled_field_name) : conditional_fields_item_apply_theme($form[$controlled_field_name]); + conditional_fields_item_apply_theme($form[$controlled_field_name], ($is_group ? $controlled_field_name : '')); } + // Add fields to javascript settings // TODO: Use unique ids (requires per-widget settings) $js_controlled_field_id = '#conditional-' . conditional_fields_form_clean_id($controlled_field_name); @@ -766,9 +839,15 @@ function conditional_fields_node_after_b // Since required fields validation is hardcoded in _form_validate, // we need to unset the #required property and perform a custom validation. foreach ($required_fields as $field) { - if ($field['in_group']) { - conditional_fields_custom_required_field($form[$field['in_group']][$field['field']]); - conditional_fields_item_apply_theme($form[$field['in_group']][$field['field']]); + if (array_key_exists($field['in_group'], $fieldsets) && is_array($fieldsets[$field['in_group']]) && array_key_exists($field['field'], $fieldsets[$field['in_group']])){ + if (is_array($fieldsets[$field['in_group']]['#group_fields'])){ + conditional_fields_custom_required_field($fieldsets[$field['in_group']]['#group_fields'][$field['field']]); + conditional_fields_item_apply_theme($fieldsets[$field['in_group']]['#group_fields'][$field['field']]); + } + else { + conditional_fields_custom_required_field($fieldsets[$field['in_group']][$field['field']]); + conditional_fields_item_apply_theme($fieldsets[$field['in_group']][$field['field']]); + } } else { conditional_fields_custom_required_field($form[$field['field']]); @@ -826,26 +905,35 @@ function conditional_fields_item_apply_t * Find an item in a form by key. If it's a CCK field, the function * will find it using field_info. */ -function conditional_fields_item_in_form($form, $item_name, $group = FALSE) { +function conditional_fields_item_in_form($form, $item_name, $group = FALSE, $fieldsets = NULL) { static $items; if (!empty($items[$item_name])) { return $items[$item_name]; } + $haystack = $form; + + if (is_array($fieldsets) && !array_key_exists($item_name, $haystack)){ + $haystack = $fieldsets; + } + if ($group) { - if (!empty($form[$group][$item_name])) { - $items[$item_name] = $form[$group][$item_name]; + if ($haystack[$group][$item_name]) { + $items[$item_name] = $haystack[$group][$item_name]; + } + elseif ($haystack[$group][$form['#field_info'][$item_name]['display_settings']['parent']][$item_name]) { + $items[$item_name] = $haystack[$group][$form['#field_info'][$item_name]['display_settings']['parent']][$item_name]; } - elseif (!empty($form[$group][$form['#field_info'][$item_name]['display_settings']['parent']][$item_name])) { - $items[$item_name] = $form[$group][$form['#field_info'][$item_name]['display_settings']['parent']][$item_name]; + else if (is_array($haystack[$group]['#group_fields']) && array_key_exists($item_name, $haystack[$group]['#group_fields'])) { + $items[$item_name] = $haystack[$group]['#group_fields'][$item_name]; } } else { - if (!empty($form[$item_name])) { - $items[$item_name] = $form[$item_name]; + if ($haystack[$item_name]) { + $items[$item_name] = $haystack[$item_name]; } - elseif (!empty($form[$form['#field_info'][$item_name]['display_settings']['parent']][$item_name])) { - $items[$item_name] = $form[$form['#field_info'][$item_name]['display_settings']['parent']][$item_name]; + elseif ($haystack[$form['#field_info'][$item_name]['display_settings']['parent']][$item_name]) { + $items[$item_name] = $haystack[$form['#field_info'][$item_name]['display_settings']['parent']][$item_name]; } } @@ -875,6 +963,11 @@ function conditional_fields_node_editing conditional_fields_add_js($form['#conditional_fields']['settings']); } + // Find all fieldsets in the form array via a recursive function + // Doing this is better than recursively walking the $form array foreach field in the $data array + $fieldsets = array(); + conditional_fields_node_editing_form_get_fieldgroups($form, $fieldsets); + // Rebuild the array grouping the data by controlled fields // Needed to handle multiple controlling field per controlled field $controlled_fields = array(); @@ -882,6 +975,8 @@ function conditional_fields_node_editing $controlled_fields[$row['field_name']][$row['control_field_name']] = $row['trigger_values']; } + $required_fields = $form['#conditional_fields']['required_fields']; + foreach ($controlled_fields as $controlled_field_name => $controlling_fields) { // Check if all controlling field were triggered $triggered = FALSE; @@ -895,10 +990,10 @@ function conditional_fields_node_editing $required_fields = $form['#conditional_fields']['required_fields']; if (!empty($required_fields[$controlled_field_name]['in_group'])) { - $controlled_field = &$form[$required_fields[$controlled_field_name]['in_group']][$controlled_field_name]; + $controlled_field = &$fieldsets[$required_fields[$controlled_field_name]['in_group']][$controlled_field_name]; } else { - $controlled_field = &$form[$controlled_field_name]; + $controlled_field = &$fieldsets[$controlled_field_name]; } // Controlled field @@ -1291,12 +1386,12 @@ function conditional_fields_set_required * Unset the #required property and set a #conditional_fields_required property for custom validation. */ function conditional_fields_custom_required_field(&$field) { - if ($field['#required']) { + if (isset($field['#required'])) { unset($field['#required']); $field['#conditional_fields_required'] = TRUE; } foreach (element_children($field) as $child) { - conditional_fields_custom_required_field($field[$child]); + if (is_array($field[$child])) conditional_fields_custom_required_field($field[$child]); } } @@ -1399,3 +1494,47 @@ function conditional_fields_form_clean_i $id = str_replace(array('][', '_', ' '), '-', $id); return $id; } + +/** +* Retuns group array from a name +*/ +function conditional_fields_get_item_group($groups, $group_name, $content) { + $group = $group_name; + $group_chain = array(); + + while ($group != "") { + array_unshift($group_chain, $group); + $group = $groups[$group]["parent"]; + } + + $groupref = &$content; + + foreach ($group_chain as $group) { + $groupref = &$groupref[$group]['group']; + } + + return $groupref; +} + +/** +* Hides field within a group or nested group +*/ + +function conditional_fields_hide_field_node_viewing($groups, $group_name, &$content, $field_name) { + $group = $group_name; + $group_chain = array(); + + while ($group != "") { + array_unshift($group_chain, $group); + $group = $groups[$group]["parent"]; + } + + $groupref = &$content; + + foreach ($group_chain as $group) { + $groupref = &$groupref[$group]['group']; + } + + $groupref[$field_name]['field']['#access'] = FALSE; +} +