From 03f0d951af13335218e0505a35ceb988437d9bcc Mon Sep 17 00:00:00 2001 From: Karen Stevenson Date: Mon, 31 Jan 2011 12:28:07 +0000 Subject: [PATCH] #849420 Additional tweaks to nested fieldgroups so they work even if nested inside fieldsets not created by CCK. Also makes it possible to nest multigroups inside groups/fieldsets that are vertical tabs, so long as the multigroup itself is not a vertical tab. --- CHANGELOG.txt | 1 + content.module | 84 ++++++++++++++++++++ includes/content.node_form.inc | 74 +----------------- .../content_multigroup.node_form.inc | 7 +- 4 files changed, 90 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 78af048..a851e5f 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -4,6 +4,7 @@ CCK 6.x-3.x =========== Features: +- #849420 by Roberto Gerola, rconstantine, thekevinday, ericduran, KarenS Add ability to nest fieldgroups within other fieldgroups. - #1008184 by merlinofchaos, bojanz, dereine, yched: Adapt to Views 3 "semantic views" feature (backwards compatible with Views 2) - #932680 by Dave Reid: Token integration : allow using of Token API's new $options - #863226 by KarenS, make sure we have a function that will return inactive instances when other instances of the same field are still active. diff --git a/content.module b/content.module index 809a144..e62ef48 100644 --- a/content.module +++ b/content.module @@ -2769,4 +2769,88 @@ function content_inactive_instances($type_name = NULL) { return $inactive[$type_name]; } return $inactive; +} + +/** + * Return the nested form elements for a field by name. + * This can be used either to retrieve the entire sub-element + * for a field by name, no matter how deeply nested it is within + * fieldgroups or multigroups, or to find the multiple value + * sub-elements within a field element by name (i.e. 'value' or + * 'nid'). You can also use this function to see if an item exists + * in a form (the return will be an empty array if it does not exist). + * + * A field/group will generally only exist once in a form but the + * function can also be used to locate all the 'value' elements + * within a multiple value field if you pass the multiple value field + * as the $form argument; + * + * For example, for a field named field_custom, the following will + * pluck out the form element for this field from the node form, + * no matter how deeply it is nested within fieldgroups or fieldsets: + * + * $element = array_shift(content_get_nested_elements($node_form, 'field_custom')); + * + * You can prefix the function with '&' to retrieve the element by + * reference to alter it directly: + * + * $elements = &content_get_nested_elements($form, 'field_custom'); + * foreach ($elements as $element) { + * $element['#after_build'][] = 'my_field_afterbuild'; + * } + * + * During the #after_build you could then do something like the + * following to alter each individual part of a multiple value field: + * + * $sub_elements = &content_get_nested_elements($element, 'value', 'all'); + * foreach ($sub_elements as $sub_element) { + * $sub_element['#element_validate'][] = 'custom_validation'; + * } + * + * @param $form + * The form array to search. + * @param $field_name + * The name or key of the form elements to return. Can be a field name, a group name, or a sub-field. + * @return + * An array of all matching form elements, returned by reference. + */ +function &content_get_nested_elements(&$form, $field_name) { + $elements = array(); + foreach (element_children($form) as $key) { + if ($key === $field_name) { + $elements[] = &$form[$key]; + } + else if (is_array($form[$key])) { + $nested_form = &$form[$key]; + if ($sub_elements = &content_get_nested_elements($nested_form, $field_name)) { + $elements = array_merge($elements, $sub_elements); + } + } + } + return $elements; +} + +/** + * Helper function to set a value in a form element, + * no matter how deeply nested it is in the form. + * + * @param $form + * The form array to search. + * @param $field_name + * The name or key of the form elements to return. Can be a field name, a group name, or a sub-field. + * @param $value + * The value to set the element to. Should be an array that matches the part of the form that is being altered. + * @return + * TRUE or FALSE, depending on whether the element was discovered and set. + */ +function content_set_nested_elements(&$form, $field_name, $value) { + $success = FALSE; + $elements = &content_get_nested_elements($form, $field_name); + if (!empty($elements)) { + foreach ($elements as &$element) { + $element = $value; + $success = TRUE; + } + } + return $success; } \ No newline at end of file diff --git a/includes/content.node_form.inc b/includes/content.node_form.inc index 67b1c2d..6ae9b69 100644 --- a/includes/content.node_form.inc +++ b/includes/content.node_form.inc @@ -477,7 +477,7 @@ function content_add_more_js($type_name_url, $field_name) { drupal_alter('form', $data, 'content_add_more_js'); // Add the new element at the right place in the (original, unbuilt) form. - content_set_form_element($field_name, $type['type'], $form, $form_element[$field_name]); + $success = content_set_nested_elements($form, $field_name, $form_element[$field_name]); // Save the new definition of the form. $form_state['values'] = array(); @@ -494,7 +494,7 @@ function content_add_more_js($type_name_url, $field_name) { $form = form_builder($_POST['form_id'], $form, $form_state); // Render the new output. - $field_form = content_get_form_element($field_name, $type['type'], $form); + $field_form = array_shift(content_get_nested_elements($form, $field_name)); // We add a div around the new content to receive the ahah effect. $field_form[$delta]['#prefix'] = '
'. (isset($field_form[$delta]['#prefix']) ? $field_form[$delta]['#prefix'] : ''); @@ -519,73 +519,3 @@ function content_add_more_js($type_name_url, $field_name) { print drupal_to_js(array('status' => TRUE, 'data' => $output)); exit; } - -/** - * Store an element into a form. - * - * @param $name - * The field name. - * @param $type - * The content type where the field instance belongs to. - * @param $form - * The form to store this field element into. - * @param $element - * The form element to store. - */ -function content_set_form_element($name, $type, &$form, $element) { - $is_group = substr($name, 0, 6) == 'group_'; - if (module_exists('fieldgroup') && ($parents = fieldgroup_get_parents($type, $name))) { - $reference = &$form; - if ($is_group) { - array_shift($parents); - $parents = array_reverse($parents); - } - else { - $parents = array_reverse($parents); - } - - foreach (array_values($parents) as $group_name) { - $reference = &$reference[$group_name]; - } - - $reference[$name] = $element; - - } - else { - $form[$name] = $element; - } -} - -/** - * Retrieve an element from a form. - * - * @param $name - * The field name. - * @param $type - * The content type where the field instance belongs to. - * @param $form - * The form to retrieve this field element from. - */ -function content_get_form_element($name, $type, $form) { - $is_group = substr($name, 0, 6) == 'group_'; - if (module_exists('fieldgroup') && ($parents = fieldgroup_get_parents($type, $name))) { - $reference = &$form; - if ($is_group) { - array_shift($parents); - $parents = array_reverse($parents); - } - else { - $parents = array_reverse($parents); - } - - foreach (array_values($parents) as $group_name) { - $reference = &$reference[$group_name]; - } - - return $reference[$name]; - } - else { - return $form[$name]; - } -} - diff --git a/modules/content_multigroup/content_multigroup.node_form.inc b/modules/content_multigroup/content_multigroup.node_form.inc index 55ae60e..4f5f414 100644 --- a/modules/content_multigroup/content_multigroup.node_form.inc +++ b/modules/content_multigroup/content_multigroup.node_form.inc @@ -142,7 +142,7 @@ function content_multigroup_group_form(&$form, &$form_state, $group, $delta) { $group_name = $group['group_name']; if (!isset($form[$group_name])) {//nested AHAH, not initial build - $element[$group_name] = content_get_form_element($group_name, $type_name, $form); + $element[$group_name] = array_shift(content_get_nested_elements($form, $group_name)); } else {//initial build (via content_multigroup_fieldgroup_form) or non-nested AHAH $element[$group_name] = $form[$group_name]; @@ -751,7 +751,6 @@ function content_multigroup_add_more_js($type_name_url, $group_name) { $content_type = content_types($type_name_url); $groups = fieldgroup_groups($content_type['type']); $group = $groups[$group_name]; - $parents = fieldgroup_get_parents($content_type['type'], $group_name); if (($group['settings']['multigroup']['multiple'] != 1) || empty($_POST['form_build_id'])) { // Invalid request. @@ -811,7 +810,7 @@ function content_multigroup_add_more_js($type_name_url, $group_name) { } } // Add the new element at the right place in the (original, unbuilt) form. - content_set_form_element($group_name, $content_type['type'], $form, $form_element[$group_name]); + $success = content_set_nested_elements($form, $group_name, $form_element[$group_name]); // Save the new definition of the form. $form_state['values'] = array(); @@ -828,7 +827,7 @@ function content_multigroup_add_more_js($type_name_url, $group_name) { $form = form_builder($_POST['form_id'], $form, $form_state); // Render the new output. - $group_form = content_get_form_element($group_name, $content_type['type'], $form); + $group_form = array_shift(content_get_nested_elements($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'] : ''); -- 1.7.4.1