--- /home/xen/tmp/test/sites/all/modules/flexifield/flexifield-widget.inc 2010-11-22 15:03:09.588819508 +0100 +++ flexifield-widget.inc 2010-11-22 14:40:44.740818071 +0100 @@ -8,7 +8,7 @@ */ /** - * Process the fieldset that contains the child fields. + * Process the fieldset that contains the child fields. */ function flexifield_fieldset_process($aElement, $aSubmittedElementData, $aFormState, $aForm) { // Ensure we have a valid content type with valid type information @@ -16,7 +16,7 @@ function flexifield_fieldset_process($aE if (!$sContentType) {return $aElement;} $aContentTypeInfo = content_types($sContentType); if (!$aContentTypeInfo) {return $aElement;} - + // For each field in that content type, add its widget form as a child of this element if (!isset($aForm['#node'])) { $aForm['#node'] = new stdClass(); @@ -35,23 +35,54 @@ function flexifield_fieldset_process($aE } } drupal_alter('flexifield_child_fields_form', $aElement, $aForm, $aFormState); - + // Hack for having $aForm['#field_info'] be what it needs to be inside each of // the widgets' #process functions. _flexifield_setup_form_field_info_hack($aElement, $aContentTypeInfo['fields']); - + + // Prevent empty submited sub form element to have any required elements + if (!empty($aSubmittedElementData)) { + // Construct pseudo item + $sItem = array( + 'value' => $aSubmittedElementData, + 'type' => $sContentType, + ); + $sFieldSettings = $aForm['#field_info'][$aElement['#field_name']]; + if (flexifield_content_is_empty($sItem, $sFieldSettings)) { + _flexifield_fieldset_clear_required($aElement); + } + } + return $aElement; } /** - * Setup the result of content_multiple_values_form() for both the + * Clear required flag of a field and all its children + */ +function _flexifield_fieldset_clear_required(&$elements) { + // Recurse through all children. + foreach (element_children($elements) as $key) { + if (isset($elements[$key]) && $elements[$key]) { + _flexifield_fieldset_clear_required($elements[$key], $form_state); + } + } + if (isset($elements['#required']) && $elements['#required']) { + $elements['#required'] = FALSE; + } + if (isset($elements['#flexifield_storage']['#field_info']['required']) && $elements['#flexifield_storage']['#field_info']['required']) { + $elements['#flexifield_storage']['#field_info']['required'] = FALSE; + } +} + +/** + * Setup the result of content_multiple_values_form() for both the * flexifield field and child fields to have some extra stuff happen * during form building (#process). */ function _flexifield_alter_multiple_values_form(&$aElement, &$aForm, &$aFormState, $aField, $aItems = array()) { $aElement['#process'] = array_merge(array('_flexifield_alter_multiple_values_form_process'), flexifield_get_element_property($aElement, '#process', array())); $aElement['#field_name'] = $aField['field_name']; - + // For the #process function to work, we need to set #input, // but doing so affects #value, and we want to be able to // clean that up. @@ -62,26 +93,28 @@ function _flexifield_alter_multiple_valu $aElement['#flexifield_value_original'] = isset($aElement['#value']) ? $aElement['#value'] : null; if (!isset($aElement['#type'])) { $aElement['#type'] = 'markup'; + // Prevent vlaidation errors + $aElement['#validated'] = TRUE; } } } /** - * Adjust the result of content_multiple_values_form() for both the - * flexifield field and child fields. The problem is that + * Adjust the result of content_multiple_values_form() for both the + * flexifield field and child fields. The problem is that * content_multiple_values_form() sets tabledrag and AHAH up with * assumptions that aren't true when nesting fields within flexifield. */ function _flexifield_alter_multiple_values_form_process($aElement) { // Solve tabledrag issues by using our version of the theme hook. $aElement['#theme'] = 'flexifield_multiple_values'; - + // Clean up what was done by forcing #input in order to have this function run. if ($aElement['#flexifield_forced_input']) { $aElement['#input'] = $aElement['#flexifield_input_original']; $aElement['#value'] = $aElement['#flexifield_value_original']; } - + // Solve AHAH. $sId = $aElement['#id']; $sKeyAddMore = $aElement['#field_name'] . '_add_more'; @@ -96,14 +129,14 @@ function _flexifield_alter_multiple_valu /** * Hack to deal with CCK widget elements using the top level form's #field_info - * property for accessing their field information. + * property for accessing their field information. * * Using the top level form's #field_info property assumes there's only - * one field of a given field name for the entire form, and this isn't + * one field of a given field name for the entire form, and this isn't * necessarily true for fields inside of flexifield. So, what we do * here is place the #field_info information on the element, and insert * a #process function to copy this information to the top-level form - * before the element's normal #process function that will need this + * before the element's normal #process function that will need this * info. We also add a final #process function to restore the top-level * form's #field_info to its original. * @@ -114,8 +147,8 @@ function _flexifield_alter_multiple_valu function _flexifield_setup_form_field_info_hack(&$aElement, &$aFieldsInfo) { foreach (element_children($aElement) as $sKey) { if ( - isset($aElement[$sKey]['#field_name']) && - isset($aFieldsInfo[$aElement[$sKey]['#field_name']]) && + isset($aElement[$sKey]['#field_name']) && + isset($aFieldsInfo[$aElement[$sKey]['#field_name']]) && !isset($aElement[$sKey]['#flexifield_storage']['#field_info']) ) { $aProcess = flexifield_get_element_property($aElement[$sKey], '#process'); @@ -158,9 +191,9 @@ function _flexifield_setup_form_field_in * Process function that runs after the element's "real" process function. * It restores the top-level form's #field_info property. * - * Technically, we don't need to do this, because form.inc's + * Technically, we don't need to do this, because form.inc's * _form_builder_handle_input_element() function takes $aForm by value instead - * of by reference, so any changes made to it are temporary anyway. However, + * of by reference, so any changes made to it are temporary anyway. However, * this might change in the future, so let's explicitly clean up after ourselves. */ function _flexifield_restore_form_field_info($aElement, $aSubmittedElementData, $aFormState, &$aForm) { @@ -188,7 +221,7 @@ function theme_flexifield_fieldset($aEle if (!isset($aElement['#children'])) { $aElement['#children'] = NULL; } - + // We setup the ahah code on the item type selector to target the element id // that is created by theme('form_element'). Therefore, we do not want to // create this element when re-rendering from the ahah callback. @@ -214,21 +247,21 @@ function flexifield_ahah_changetype($sEl drupal_json(array('data' => '')); exit; } - + // Build the form, so that we can render the element we want. // It seems like overkill to build the entire form, when we just // want one field item from it. Perhaps this can be optimized. $aFormCopy = $aForm; $aFormCopy['#post'] = $_POST; $aBuiltForm = form_builder($_POST['form_id'], $aFormCopy, $aFormState); - + // Get just the element that needs re-rendering. $aElement = $aBuiltForm; foreach (explode(':', $sElementParents) as $sParent) { $aElement = $aElement[$sParent]; } $aElement = $aElement['value']; - + // Return the rendered element as an ahah response $aElement['#flexifield_from_ahah'] = TRUE; print theme('ahah_response', drupal_render($aElement)); @@ -239,19 +272,19 @@ function flexifield_ahah_changetype($sEl * Menu callback for adding another item to a multi-valued field. * Used for both flexifields and fields within flexifield. */ -function flexifield_ahah_addmore($sTypeNameUrl, $sFieldName, $sParents, $sDataParents) { +function flexifield_ahah_addmore($sTypeNameUrl, $sFieldName, $sParents, $sDataParents) { $aParents = explode(':', $sParents); while (array_pop($aParents) != $sFieldName) {} $aDataParents = explode(':', $sDataParents); while (array_pop($aDataParents) != $sFieldName) {} - + // If this is the root flexifield, then use content.module's way of // adding another item (with a small modification). if (!count($aParents)) { module_load_include('inc', 'flexifield', 'flexifield-cck-overrides'); return flexifield_add_more_js($sTypeNameUrl, $sFieldName); } - + // Retrieve the cached form. $aFormState = array('submitted' => FALSE); $sFormBuildId = $_POST['form_build_id']; @@ -261,7 +294,7 @@ function flexifield_ahah_addmore($sTypeN drupal_json(array('data' => '')); exit; } - + // Build the form, so that we can render the element we want. // It seems like overkill to build the entire form, when we just // want one field item from it. Perhaps this can be optimized. @@ -273,14 +306,14 @@ function flexifield_ahah_addmore($sTypeN } $aFormPostReference[$sFieldName][] = array(); $aBuiltForm = form_builder($_POST['form_id'], $aFormCopy, $aFormState); - + // Get just the element that needs re-rendering. $aElement = $aBuiltForm; foreach ($aParents as $sParent) { $aElement = $aElement[$sParent]; } $aElement = $aElement[$sFieldName]; - + // Return the rendered element as an ahah response $sRenderedElement = drupal_render($aElement); print theme('ahah_response', $sRenderedElement);