Index: explainfield.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/explainfield/explainfield.module,v
retrieving revision 1.1.2.6.2.2
diff -u -r1.1.2.6.2.2 explainfield.module
--- explainfield.module	9 Dec 2007 15:21:34 -0000	1.1.2.6.2.2
+++ explainfield.module	15 Dec 2007 00:13:54 -0000
@@ -1,4 +1,176 @@
 <?php
+     
+/*
+ * Implementation of hook_form_alter()
+ */
+function explainfield_form_alter($form_id, &$form) {
+  if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id) {
+    $type_name = $form['#node']->type;
+    
+    /* Check if node type has field groups */
+    if (!$groups = fieldgroup_groups($type_name))
+      return;
+    /* Check if we are in a content type administration page */
+    if ($form['#node']->cck_dummy_node_form == TRUE)
+      return;
+      
+    $type = content_types($type_name);
+
+    foreach ($type['fields'] as $field_name => $field) {
+      if ($field['type'] == 'explainfield' && 
+          $field['explain_field_choice'] == 'field_group') {
+
+        $group = $form[$groups[$field['explain_group_select']]['group_name']];    
+          
+        /* jQuery looks for this div to show/hide the explainfield */
+        $group['#prefix'] = '<div id="explainfield-'. _misc_formize($field_name) .'">';
+        $group['#suffix'] = '</div>';
+        
+        /* 
+         * We scan through the fields and set them as not required, as they
+         * must be required only if the trigger key is selected. We check
+         * build an array of required fields in $explainfield_required_fields
+         * so that we can check them later in explainfield_nodeapi (validate).
+         */
+        $widget_types = _content_widget_types();
+        $explainfield_required_fields = array();
+        $required_markup = '<span class="form-required" title="'. t('This field is required.') .'">*</span>';
+        foreach (element_children($group) as $child_name) {
+          foreach (element_children($group[$child_name]) as $subchild_name) {
+            /* We can do better than this. $type['fields'][$child_name]['type'] is
+             * the widget type...
+             */             
+            /* Check for: select, checkboxes, radio fields */
+            if ($group[$child_name][$subchild_name]['#required'] == 1) {
+              $group[$child_name][$subchild_name]['#required'] = 0;
+              $group[$child_name][$subchild_name]['#title'] .= $required_markup;
+              $explainfield_required_fields[$child_name] = TRUE;
+            }
+            /* Check for: text fields */
+            else if ($group[$child_name][$subchild_name]['value']['#required'] == 1) {
+              $group[$child_name][$subchild_name]['value']['#required'] = 0;
+              $group[$child_name][$subchild_name]['value']['#title'] .= $required_markup;
+              $explainfield_required_fields[$child_name] = TRUE;              
+            }
+            /* Check for: link (link.module). */
+            else if ($widget_types['link']) {
+              if ($group[$child_name][$subchild_name]['url']['#required'] == 1) {
+                $group[$child_name][$subchild_name]['url']['#required'] = 0;
+                $group[$child_name][$subchild_name]['url']['#title'] .= $required_markup;
+                $explainfield_required_fields[$child_name]['url'] = TRUE;
+              }  
+              if ($group[$child_name][$subchild_name]['title']['#required'] == 1) {  
+                $group[$child_name][$subchild_name]['title']['#required'] = 0;
+                $group[$child_name][$subchild_name]['title']['#title'] .= $required_markup;
+                $explainfield_required_fields[$child_name]['title'] = TRUE;
+              }
+            }
+            /* We could add support for more widget types here... */ 
+            /*
+            else if ($widget_types['']) {
+              if ($group[$child_name][$subchild_name]['']['#required'] == 1) {
+                $group[$child_name][$subchild_name]['']['#required'] = 0;
+                $group[$child_name][$subchild_name]['']['#title'] .= $required_markup;
+                $explainfield_required_fields[$child_name][''] = TRUE;
+              }
+            }
+            */
+          }
+        }
+        
+        $form['#explainfield_required_fields'] = $explainfield_required_fields;
+        $form[$groups[$field['explain_group_select']]['group_name']] = $group;
+      }
+    }
+  }
+}
+
+/*
+ * Implementation of hook_nodeapi()
+ */
+function explainfield_nodeapi(&$node, $op, $teaser, $page) {
+  
+  /* Since the following code relies on fieldgroup.module, there is nothing to
+   * do if that module is not enabled.
+   */   
+  if (!module_exists('fieldgroup'))
+    return;
+
+  switch ($op) {
+    case 'validate':
+      /* The $teaser variable in this case contains the passing form. */
+      $form = $teaser;
+      
+      $type = content_types($node->type);
+
+      foreach ($type['fields'] as $field_name => $field) {
+        if ($field['type'] == 'explainfield' && $field['explain_field_choice'] == 'field_group' && $form[$field['explain_group_select']]) {
+          
+          /* If a trigger key was selected, then we must respect the 'required'
+           * setting of the group fields.
+           */           
+          if (explainfield_is_triggered($node->$field_name, $field['trigger_value']) == TRUE) {
+            foreach ($form['#explainfield_required_fields'] as $field_name => $is_required) {
+              explainfield_check_required($form[$field['explain_group_select']], $field_name, $field);
+            }
+          } 
+        }
+      }
+      break;
+
+    case 'view':
+      $type_name = $node->type;
+
+      /* Check if node type has field groups */
+      if (!$groups = fieldgroup_groups($type_name))
+        break;
+
+      $type = content_types($type_name);
+
+      foreach ($type['fields'] as $field) {
+        if ($field['type'] == 'explainfield' && $field['explain_field_choice'] == 'field_group' && $node->content[$field['explain_group_select']]) {
+          $teaser == TRUE ? $context = 'teaser' : $context = 'full';
+
+          if ($field['display_settings'][$context]['format'] == 'valueonly' || $field['display_settings'][$context]['format'] == 'hidden' || explainfield_is_triggered($node->$field['field_name'], $field['trigger_value']) == FALSE) {
+            unset($node->content[$field['explain_group_select']]);
+          }
+        }
+      }
+    break;
+  }
+}
+
+/* 
+ * Returns TRUE if the trigger keys of an explainfield were selected in the 
+ * node editing form.
+ * $field is from $node->$field_name,
+ * $keys is from $field['trigger_value']
+ */
+function explainfield_is_triggered($field, $keys) {
+  foreach (explode(',', $keys) as $key) {
+    if ($key == $field[0]['value'])
+      return TRUE;
+  }
+  return FALSE;
+}
+
+/*
+ * Scans through the fields of a fieldgroup, and sets form error for empty fields.
+ */
+function explainfield_check_required($group, $field_name) {
+  foreach (element_children($group[$field_name]) as $child) {
+    if ((string)$child != 'format' && !(is_integer($child) && $child > 0)) {
+      if (!$group[$field_name][$child]['#type'] || $group[$field_name][$child]['#type'] == 'fieldset') {
+        explainfield_check_required($group[$field_name], $child);
+      }
+    else {
+        if (empty($group[$field_name][$child]['#value']) && $group[$field_name][$child]['#value'] !== '0') {
+          form_error($group[$field_name][$child], t('!name field is required.', array('!name' => $group[$field_name][$child]['#title'])));
+        }
+      }
+    }
+  }
+}
 
 /**
  * Implementation of hook_field_info().
@@ -10,30 +182,30 @@
 }
 
 function explainfield_field_settings($op, $field) {
-  switch($op) {
+  switch ($op) {
   case 'form':
     $form = array();
     $form['allowed_values'] = array(
-        '#type' => 'textarea',
-        '#title' => t('Allowed values list'),
-        '#default_value' => isset($field['allowed_values']) ? $field['allowed_values'] : '',
-        '#required' => FALSE,
-        '#multiple' => FALSE,
-        '#rows' => 5,
-        '#description' => t('The possible values this field can contain. Enter one value per line, in the format key|label. The key is the value that will be stored in the database and it must match the field storage type, %type. The label is optional and the key will be used as the label if no label is specified.', array('%type' => $field['type'])),
-      );
-   $form['advanced_options'] = array(
-        '#type' => 'fieldset',
-        '#title' => t('Php code'),
-        '#collapsible' => TRUE,
-        '#collapsed' => TRUE,
-   );
-   $form['advanced_options']['allowed_values_php'] = array(
-        '#type' => 'textarea',
-        '#title' => t('Code'),
-        '#default_value' => $field['allowed_values_php'],
-        '#rows' => 6,
-        '#description' => t('Advanced Usage Only: PHP code that returns a keyed array of allowed values. Should not include &lt;?php ?&gt; delimiters. If this field is filled out, the array returned by this code will override the allowed values list above.'),
+      '#type' => 'textarea',
+      '#title' => t('Allowed values list'),
+      '#default_value' => isset($field['allowed_values']) ? $field['allowed_values'] : '',
+      '#required' => FALSE,
+      '#multiple' => FALSE,
+      '#rows' => 5,
+      '#description' => t('The possible values this field can contain. Enter one value per line, in the format key|label. The key is the value that will be stored in the database and it must match the field storage type, %type. The label is optional and the key will be used as the label if no label is specified.', array('%type' => $field['type'])),
+    );
+    $form['advanced_options'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Php code'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+    );
+    $form['advanced_options']['allowed_values_php'] = array(
+      '#type' => 'textarea',
+      '#title' => t('Code'),
+      '#default_value' => $field['allowed_values_php'],
+      '#rows' => 6,
+      '#description' => t('Advanced Usage Only: PHP code that returns a keyed array of allowed values. Should not include &lt;?php ?&gt; delimiters. If this field is filled out, the array returned by this code will override the allowed values list above.'),
     );
     $form['trigger_value'] = array(
       '#type' => 'textfield',
@@ -48,14 +220,28 @@
       '#collapsible' => TRUE,
       '#collapsed' => FALSE,
       );
-    $form['explain_options']['explain_label'] = array(
+    $form['explain_options']['explain_field_choice'] = array(
+      '#type' => 'radios',
+      '#title' => t('Type of explain field'),
+      '#default_value' => isset($field['explain_field_choice']) ? $field['explain_field_choice'] : 'field_help_text',
+      '#options' => array('field_help_text' => t('Simple help text field'), 'field_group' => t('Field group')),
+      '#required' => TRUE,
+    );
+    $form['explain_options']['explain_choice_help_text'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Help Text'),
+      '#collapsible' => TRUE,
+      '#collapsed' => $field['explain_field_choice'] == 'field_help_text' ? FALSE : TRUE,
+      '#description' => t('These settings are used only if you select the \'Simple help text field\' option above.'),
+      );
+    $form['explain_options']['explain_choice_help_text']['explain_label'] = array(
       '#type' => 'textfield',
       '#title' => 'Label',
       '#default_value' => isset($field['explain_label']) ? $field['explain_label'] : '',
       '#required' => FALSE,
       '#description' => t('Label that will appear over the explain field, and when viewing the node.'),
     );
-    $form['explain_options']['explain_text'] = array(
+    $form['explain_options']['explain_choice_help_text']['explain_text'] = array(
       '#type' => 'textarea',
       '#title' => 'Help text for the explain field',
       '#default_value' => isset($field['explain_text']) ? $field['explain_text'] : '',
@@ -63,23 +249,55 @@
       '#rows' => 3,
       '#description' => t('Instructions on what to write into the appearing explain field.'),
     );
-    $form['explain_options']['max_length'] = array(
+    $form['explain_options']['explain_choice_help_text']['max_length'] = array(
         '#type' => 'textfield',
         '#title' => t('Maximum length'),
         '#default_value' => isset($field['max_length']) ? $field['max_length'] : '',
         '#required' => FALSE,
         '#description' => t('The maximum length of the field in characters. Leave blank for an unlimited size.'),
       );
-    $form['explain_options']['explain_rows'] = array(
+    $form['explain_options']['explain_choice_help_text']['explain_rows'] = array(
       '#type' => 'textfield',
       '#title' => t('Textfield size'),
       '#default_value' => isset($field['explain_rows']) ? $field['explain_rows'] : '',
       '#required' => FALSE,
       '#description' => t('The height of the explain field. Leave blank for default 3.'),
     );
+    
+    if (module_exists('fieldgroup')) {
+      $group_descrition = t('You can choose any group assigned to this content type. The selected group will be only displayed if a trigger key is selected when you create or edit the node. These settings are used only if you select the \'Field group\' option above.');
+      
+      $available_groups = fieldgroup_groups($content_type = $field['type_name']);
+      foreach ($available_groups as $group) {
+        $available_groups_options[$group['group_name']] = $group['label'];
+      }
+    }
+    else {
+      $group_descrition = t('You should activate the <a href="@modules">fieldgroup</a> module to use this option.', array('@modules' => url('admin/build/modules', NULL, 'edit-status-fieldgroup')));
+      $available_groups_options = array('none' => t('None'));
+    }
+    
+    $form['explain_options']['explain_choice_group'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Group'),
+      '#collapsible' => TRUE,
+      '#collapsed' => $field['explain_field_choice'] == 'field_group' ? FALSE : TRUE,
+      '#description' => $group_descrition,
+    );
+    
+    $form['explain_options']['explain_choice_group']['explain_group_select'] = array(
+      '#type' => 'select',
+      '#title' => t('Select group'),
+      '#default_value' => isset($field['explain_group_select']) ? $field['explain_group_select'] : NULL,
+      '#multiple' => FALSE,
+      '#options' => $available_groups_options,
+      '#required' => FALSE,
+      '#description' => t('Go to the <a href="@manage">Manage fields</a> page to edit groups, or to the <a href="@add">Add group</a> page to create one.', array('@manage' => url('admin/content/types/'. $field['type_name'] .'/fields'), '@add' => url('admin/content/types/'. $field['type_name'] .'/add_group'))),
+    );
+    
     return $form;
   case 'save':
-    return array('allowed_values', 'allowed_values_php', 'trigger_value', 'explain_text', 'explain_rows', 'explain_label', 'max_length');
+    return array('allowed_values', 'allowed_values_php', 'trigger_value', 'explain_field_choice', 'explain_text', 'explain_rows', 'explain_label', 'max_length', 'explain_group_select');
   case 'database columns':
     $columns = array(
       'value' => array('type' => 'longtext', 'not null' => TRUE, 'default' => "''", 'sortable' => TRUE),
@@ -90,7 +308,7 @@
       $triggers = explode(',', $field['trigger_value']);
       /* Check if trigger is set correctly */
       $values = explode("\n", $field['allowed_values']);
-      foreach($values as $n => $line) {
+      foreach ($values as $n => $line) {
         $values[$n] = explode('|', $line);
         $trimmed = trim($values[$n][0]);
         $carriageremoved = str_replace("\r", "", $trimmed);
@@ -98,13 +316,16 @@
         $keys[] = $newlineremoved;
       }
       foreach ($triggers as $trigger) {
-        if(!in_array($trigger, $keys)) {
+        if (!in_array($trigger, $keys)) {
           $error[] = $trigger;
         }
       }
       if ($error) {
         form_set_error('trigger_value', t('Incorrect trigger keys are set: %keys', array('%keys' => implode(', ', $error))));
       }
+      if ($field['explain_field_choice'] == 'field_group' && $field['explain_group_select'] == 'none') {
+        form_set_error('explain_group_select', t('You should create a group before chosing this option.'));      
+      }
       break;
     case 'filters':
       return array(
@@ -166,21 +387,26 @@
       unset($item['explainfield']);
       $text = strip_tags($values);
       break;
-                
     case 'default':
-    
-			$class = isset($field['']) ? '-inline' : '';
-            $explanation = (!empty($field['explain_label']) && !(empty($item['explainfield']))) ? '<div class="field-label'.$class.'">' . $field['explain_label'] . ': </div><div class="field-items">'.  check_plain($item['explainfield']) . '</div>' : '';
-			return check_plain($values) . $explanation;
-			break;
+      $class = isset($field['']) ? '-inline' : '';
+
+      if ($field['explain_field_choice'] == 'field_group') {
+        return check_plain($values);
+      }
+      else {
+        $explanation = (!empty($field['explain_label']) && !(empty($item['explainfield']))) ? '<div class="field-label'. $class .'">'. $field['explain_label'] .': </div><div class="field-items">'.  check_plain($item['explainfield']) .'</div>' : '';
+        return check_plain($values) . $explanation;
+      }
+      
+      break;
     case 'replace':
       $explanation = !empty($item['explainfield']) ? check_plain($item['explainfield']) : '';
 
       /** If the key is the trigger key output the explanation only. In this case
        * $explanation is set, because we validate for this at form submission 
        */
-      $triggers = explode(',',$field['trigger_value']);
-        if(in_array($item['value'], $triggers)) { $text = $explanation; }
+      $triggers = explode(',', $field['trigger_value']);
+        if (in_array($item['value'], $triggers)) { $text = $explanation; }
       else {
         $text = $values;
       }
@@ -189,11 +415,11 @@
       $text = $item['explainfield'];
       break;
   }         
-	return check_plain($text);
+  return check_plain($text);
 }             
 
 function explainfield_field($op, &$node, $field, &$items, $teaser, $page) {
-  switch($op) {
+  switch ($op) {
   case 'validate':
       if ($field['max_length'] > 0) {
         foreach ($items as $delta => $data) {
@@ -212,7 +438,7 @@
  * Implementation of hook_widget_info().
  */
 function explainfield_widget_info() {
-	$option_types = array('explainfield',);
+  $option_types = array('explainfield');
   return array(
     'explainfield_select' => array(
       'label' => t('Explainfield in select list'),
@@ -225,11 +451,6 @@
   );
 }
 
-/**
- * Implementation of hook_widget_settings().
- */
-function explainfield_widget_settings() {
-}
 
 /**
  * Implementation of hook_widget().
@@ -265,6 +486,7 @@
         $items['default key'] = reset($keys);
         $items['default explain'] = $items[0]['explainfield'];
       }
+      
       break;
 
     case 'form':
@@ -274,32 +496,11 @@
 
       $form[$field['field_name']] = array('#tree' => TRUE);
       $field_name = _misc_formize($field['field_name']);
-
       switch ($field['widget']['type']) {
         case 'explainfield_select':
-          
           /* JavaScript for select */
-      
-          $code = '
-  jQuery().ready(function() {
-
-    '. explainfield_array_php_to_js('trigger_value', explode(",", $field['trigger_value'])) .'
-
-    if ( jQuery.inArray($("select#edit-'.$field_name.'-key").val(), trigger_value) == -1) {
-        $("#explainfield-'.$field_name.'").hide();
-    }
-
-    $("select#edit-'.$field_name.'-key").change( function () {
-      if ( jQuery.inArray($("select#edit-'.$field_name.'-key").val(), trigger_value) != -1) {
-        $("#explainfield-'.$field_name.'").show();
-      } else {
-        $("#explainfield-'.$field_name.'").hide();
-      }
-    });
-  
-  });
-';
-
+          $code = _explainfield_js('explainfield_select', $field, $field_name);
+    
           $form[$field['field_name']]['key'] = array(
             '#type' => 'select',
             '#title' => t($field['widget']['label']),
@@ -308,76 +509,26 @@
             '#options' => $options,
             '#required' => $field['required'],
             '#description' => t($field['widget']['description']),
-          );
-          $form[$field['field_name']]['explain'] = array(
-            '#type' => 'textarea',
-            '#title' => t($field['explain_label']),
-            '#default_value' => $items['default explain'],
-            '#rows' => isset($field['explain_rows']) ? $field['explain_rows'] : 3,
-            '#prefix' => '<div id="explainfield-'.$field_name.'">',
-            '#suffix' => '</div>',
-            '#description' => t($field['explain_text']),
-          );
+          );      
           break;
-
         case 'explainfield_buttons':
           if ($field['multiple']) {
-
-            /* JavaScript for checkbox */
-
-            /* We prepare the trigger values for jquery*/
-            $trigger_values = str_replace(array(' ', ','), array('-', ',#edit-'.$field_name.'-keys-'), '#edit-'.$field_name.'-keys-'.$field['trigger_value']);
-      
-            $code = '
-  jQuery().ready(function() {
-
-    trigger_values = "'. $trigger_values .'"
-    $("#explainfield-'.$field_name.'").hide();
-
-      if( $(trigger_values).is(":checked")) {
-        $("#explainfield-'.$field_name.'").show();
-      }
-      
-      $(trigger_values).click( function () {
-        if( $(trigger_values).is(":checked")) {
-          $("#explainfield-'.$field_name.'").show(); 
-        } else { 
-          $("#explainfield-'.$field_name.'").hide(); 
-        }
-        $(this).blur();
-      });
-  });
-</script>';
+            /* JavaScript for checkbox */  
+            $code = _explainfield_js('explainfield_checkboxes', $field, $field_name);
+              
             $form[$field['field_name']]['keys'] = array(
-              '#type' => 'checkboxes',
-              '#title' => t($field['widget']['label']),
-              '#default_value' => $items['default keys'],
-              '#options' => $options,
-              '#required' => $field['required'],
-              '#description' => t($field['widget']['description']),
-            );
-          
-          } else {
-            /* JavaScript for radiobuttons */
-                   
-            $code = '
-  jQuery().ready(function() {
-    '. explainfield_array_php_to_js('trigger_value', explode(",", $field['trigger_value'])) .'
-    if ( jQuery.inArray($(\'input[@type="radio"][@name="'.$field['field_name'].'[key]"][@checked]\').val(), trigger_value) == -1) { 
-      $("#explainfield-'.$field_name.'").hide();
-    }
-  
-    $(\'input[@type="radio"][@name="'.$field['field_name'].'[key]"]\').click( function () {
-      if ( jQuery.inArray($(this).attr(\'value\'), trigger_value) != -1) {
-                $("#explainfield-'.$field_name.'").show();
-              } else {
-                $("#explainfield-'.$field_name.'").hide();
-              }
-      $(this).blur();
-    });
-  });
-';
-            
+                '#type' => 'checkboxes',
+                '#title' => t($field['widget']['label']),
+                '#default_value' => $items['default keys'],
+                '#options' => $options,
+                '#required' => $field['required'],
+                '#description' => t($field['widget']['description']),
+            );  
+          }
+          else {
+            /* JavaScript for radiobuttons */ 
+            $code = _explainfield_js('explainfield_radios', $field_name, $field);
+             
             $form[$field['field_name']]['key'] = array(
               '#type' => 'radios',
               '#prefix' => '<div id="#edit-field-'. _misc_formize($field['widget']['label']) .'-keys">',
@@ -389,28 +540,35 @@
               '#description' => t($field['widget']['description']),
             );
           }
-          $form[$field['field_name']]['explain'] = array(
-            '#type' => 'textarea',
-            '#title' => t($field['explain_label']),
-            '#default_value' => $items['default explain'],
-            '#rows' => isset($field['explain_rows']) ? $field['explain_rows'] : 3,
-            '#prefix' => '<div id="explainfield-'.$field_name.'">',
-            '#suffix' => '</div>',
-            '#description' => t($field['explain_text']),
-          );
           break;
       }
+      
+      /* The explain field itself can be a simple help text field, or a group. */       
+      if ($field['explain_field_choice'] == 'field_help_text') {
+        $form[$field['field_name']]['explain'] = _explainfield_widget_help_text($field, $items, $field_name);
+      }
+      else if ($field['explain_field_choice'] == 'field_group') {
+        //$form[$field['field_name']]['explain'] = array();
+        $form[$field['field_name']]['explain'] = _explainfield_widget_field_group($field, $items, $field_name, $node);
+      }
+      
       drupal_add_js($code, 'inline');
       return $form;
+      
     case 'validate':
-      /** We can't set the explain field to required, because it belongs to the options. E.g. if
-       *  the user is on a non-trigger field it complains about the field being not filled.
-       *  Need to validate manually. Avoid checking in content field editing.
-       */
-      if (!is_array($node)) {
-        if(_explainfield_is_trigger_fieldcheck($items,$field)) {
-          $error_field = isset($item['error_field']) ? $item['error_field'] : $field['field_name'];
-          form_set_error($error_field, t('Please fill the optional form in %label if you select this option.', array('%label' => t($field['widget']['label'])) ));
+      if ($field['explain_field_choice'] == 'field_group') {
+      
+      }
+      else {
+        /** We can't set the explain field to required, because it belongs to the options. E.g. if
+         *  the user is on a non-trigger field it complains about the field being not filled.
+         *  Need to validate manually. Avoid checking in content field editing.
+         */
+        if (!is_array($node)) {
+          if (_explainfield_is_trigger_fieldcheck($items, $field)) {
+            $error_field = isset($item['error_field']) ? $item['error_field'] : $field['field_name'];
+            form_set_error($error_field, t('Please fill the optional form in %label if you select this option.', array('%label' => t($field['widget']['label'])) ));
+          }
         }
       }
       break;
@@ -422,7 +580,8 @@
       if ($field['multiple'] || $field['widget']['type'] == 'explainfield_onoff') {
         if ($field['widget']['type'] == 'explainfield_select') {
           $keys = $items['key'];
-        } else {
+        }
+        else {
           $keys = (array) $items['keys'];
         }
       }
@@ -440,7 +599,7 @@
       $items = content_transpose_array_rows_cols(array('value' => $values));
 
       /* Only save explanation when it is necessary (the field exists all along) */
-      if( $delta = _explainfield_is_trigger($items, $field) ) {
+      if ($delta = _explainfield_is_trigger($items, $field)) {
         $items[$delta-1]['explainfield'] = $explanation;
       }
 
@@ -451,6 +610,98 @@
   }
 }
 
+function _explainfield_widget_help_text($field, $items, $field_name) {
+  $explain_field = array(
+    '#type' => 'textarea',
+    '#title' => t($field['explain_label']),
+    '#default_value' => $items['default explain'],
+    '#rows' => isset($field['explain_rows']) ? $field['explain_rows'] : 3,
+    '#prefix' => '<div id="explainfield-'. $field_name .'">',
+    '#suffix' => '</div>',
+    '#description' => t($field['explain_text']),
+  );
+  return $explain_field;
+}
+
+function _explainfield_widget_field_group($field, $items, $field_name, &$node) {    
+      
+  /* Check if node type has field groups */
+  if (!$groups = fieldgroup_groups($node->type))
+    return _explainfield_widget_help_text($field, $items, $field_name);
+ 
+  return array();
+}
+
+function _explainfield_js($op, $field_name, $field) {
+  switch ($op) {
+    case 'explainfield_select':
+      $code = '
+  jQuery().ready(function() {
+
+    '. explainfield_array_php_to_js('trigger_value', explode(",", $field['trigger_value'])) .'
+
+    if ( jQuery.inArray($("select#edit-'. $field_name .'-key").val(), trigger_value) == -1) {
+        $("#explainfield-'. $field_name .'").hide();
+    }
+
+    $("select#edit-'. $field_name .'-key").change( function () {
+      if ( jQuery.inArray($("select#edit-'. $field_name .'-key").val(), trigger_value) != -1) {
+        $("#explainfield-'. $field_name .'").show();
+      } else {
+        $("#explainfield-'. $field_name .'").hide();
+      }
+    });
+  
+  });
+';
+      break;
+    case 'explainfield_checkboxes':
+      /* We prepare the trigger values for jquery*/
+      $trigger_values = str_replace(array(' ', ','), array('-', ',#edit-'. $field_name .'-keys-'), '#edit-'. $field_name .'-keys-'. $field['trigger_value']);
+      $code = '
+  jQuery().ready(function() {
+
+    trigger_values = "'. $trigger_values .'"
+    $("#explainfield-'. $field_name .'").hide();
+
+      if( $(trigger_values).is(":checked")) {
+        $("#explainfield-'. $field_name .'").show();
+      }
+      
+      $(trigger_values).click( function () {
+        if( $(trigger_values).is(":checked")) {
+          $("#explainfield-'. $field_name .'").show(); 
+        } else { 
+          $("#explainfield-'. $field_name .'").hide(); 
+        }
+        $(this).blur();
+      });
+  });
+</script>';
+      break;
+    case 'explainfield_radios':
+      $code = '
+  jQuery().ready(function() {
+    '. explainfield_array_php_to_js('trigger_value', explode(",", $field['trigger_value'])) .'
+    if ( jQuery.inArray($(\'input[@type="radio"][@name="'. $field['field_name'] .'[key]"][@checked]\').val(), trigger_value) == -1) { 
+      $("#explainfield-'. $field_name .'").hide();
+    }
+  
+    $(\'input[@type="radio"][@name="'. $field['field_name'] .'[key]"]\').click( function () {
+      if ( jQuery.inArray($(this).attr(\'value\'), trigger_value) != -1) {
+                $("#explainfield-'. $field_name .'").show();
+              } else {
+                $("#explainfield-'. $field_name .'").hide();
+              }
+      $(this).blur();
+    });
+  });
+';
+      break;
+  }
+  return $code;
+}
+
 function _explainfield_options($field, $node) {
   $types = _content_field_types();
   $field_allowed_values = $types[$field['type']]['module'] .'_allowed_values';
@@ -461,8 +712,7 @@
     $allowed_values = array();
   }
 
-  if ($field['widget']['type'] == 'explainfield_select' ||
-     ($field['widget']['type'] == 'explainfield_buttons' && !$field['multiple'])) {
+  if ($field['widget']['type'] == 'explainfield_select' || ($field['widget']['type'] == 'explainfield_buttons' && !$field['multiple'])) {
     if (!$field['required']) {
       $allowed_values = array('' => theme('explainfield_none', $field['widget']['type'], $field['field_name'], $node->type)) + $allowed_values;
     }
@@ -476,27 +726,26 @@
  * where $delta means where it is set
  */
 function _explainfield_is_trigger($items, $field) {
-  $triggers = explode(',',$field['trigger_value']);
+  $triggers = explode(',', $field['trigger_value']);
   foreach ($triggers as $trigger) {
-    if($field['multiple']) {
-      foreach($items as $delta => $values) {
-        if($values['value'] == $trigger) return $delta+1;
+    if ($field['multiple']) {
+      foreach ($items as $delta => $values) {
+        if ($values['value'] == $trigger) return $delta+1;
       }
     }
     else {
-      if($items[0]['value'] == $trigger) return 1;
+      if ($items[0]['value'] == $trigger) return 1;
     }
   }
   return false;
 }
 
 
-
 /**
  * Function returns true if the trigger is set, but the extra textfield is empty
  */
 function _explainfield_is_trigger_fieldcheck($items, $field) {
-  if(empty($items['key']) && empty($items['explain'])) {
+  if (empty($items['key']) && empty($items['explain'])) {
     return false;
   }
 
@@ -504,12 +753,13 @@
   
   foreach ($triggers as $trigger) {
 
-    if($field['multiple']) {
+    if ($field['multiple']) {
       $field['widget']['type'] == 'explainfield_select' ? $key_var = 'key' : $key_var = 'keys';
-      if( in_array($trigger, $items[$key_var]) && empty($items['explain']) ) { 
+      if ( in_array($trigger, $items[$key_var]) && empty($items['explain']) ) { 
         return true; 
       }
-    } else if( in_array($trigger, $items) && empty($items['explain']) ) {
+    }
+    else if ( in_array($trigger, $items) && empty($items['explain']) ) {
       return true;
     }
   }
@@ -574,12 +824,13 @@
   */
 function explainfield_array_php_to_js($name, $array) {
   if (is_array($array)) { // Array recursion
-    $result = $name.' = new Array();'."\n";
+    $result = $name .' = new Array();'."\n";
     foreach ($array as $key => $value) {
-      $result .= explainfield_array_php_to_js($name.'["'.$key.'"]',$value);
+      $result .= explainfield_array_php_to_js($name .'["'. $key .'"]', $value);
     }
-  } else {  // Base case of recursion
-    $result = $name.' = "'.$array.'";'."\n";
+  }
+  else {  // Base case of recursion
+    $result = $name .' = "'. $array .'";'."\n";
   }
   return $result;
-}
+}
\ No newline at end of file

