From 5e5770288a24c453e857362b16805a4e4004abf5 Mon Sep 17 00:00:00 2001
From: Peter <aegir@create.simplistechsolutions.com>
Date: Tue, 9 Nov 2010 14:38:52 -0600
Subject: [PATCH] working with content_taxonomy

---
 select_or_other.module |  313 +++++++++++++++++++++++++++++++-----------------
 1 files changed, 202 insertions(+), 111 deletions(-)

diff --git a/select_or_other.module b/select_or_other.module
index 46ce7cf..84ec526 100755
--- a/select_or_other.module
+++ b/select_or_other.module
@@ -108,36 +108,12 @@ function select_or_other_process($element, $edit, &$form_state, $form) {
     );
   }
 
-  // Process the default value.
-  foreach ($element['select']['#default_value'] as $key => $val) {
-    if ($val 
-        && isset($element['select']['#options']) 
-        && is_array($element['select']['#options']) 
-        && !array_key_exists($val, $element['select']['#options']) 
-        && !in_array($val, $element['select']['#options'])) {
-      // Not a valid option - add it to 'other'.
-      if ($element['#other_unknown_defaults'] == 'other') {
-        if ($element['#other_delimiter']) {
-          $other_default[] = $val;
-        }
-        else {
-          $other_default = array($val);
-        }
-        // Remove it from the select's default value.
-        unset($element['select']['#default_value'][$key]);
-      }
-      elseif ($element['#other_unknown_defaults'] == 'append') {
-        $element['select']['#options'][$val] = $val;
-      }
-
-    }
-  }
-
   // If the expected default value is a string/integer, remove the array wrapper.
   if ($element['#select_type'] == 'radios' || ($element['#select_type'] == 'select' && !$element['#multiple'])) {
     $element['select']['#default_value'] = reset($element['select']['#default_value']);
   }
 
+/* sts not sure I need this
   $other_default_string = '';
   if (!empty($other_default)) {
     $other_default_string = implode($element['#other_delimiter'], $other_default);
@@ -148,7 +124,7 @@ function select_or_other_process($element, $edit, &$form_state, $form) {
       $element['select']['#default_value'] = 'select_or_other';
     }
   }
-
+*/
   // Add in the 'other' option.
   $element['select']['#options']['select_or_other'] = $element['#other'];
 
@@ -156,7 +132,7 @@ function select_or_other_process($element, $edit, &$form_state, $form) {
   $element['other'] = array(
     '#type' => 'textfield',
     '#weight' => 20,
-    '#default_value' => $other_default_string,
+    '#default_value' => '',
     '#disabled' => $element['#disabled'],
     '#attributes' => $element['#attributes'],
   );
@@ -281,23 +257,15 @@ function select_or_other_widget_info() {
   return array(
     'select_or_other' => array(
       'label' => t('Select (or other) list'),
-      'field types' => array('text', 'number_integer', 'number_decimal', 'number_float'),
+      'field types' => array('text', 'number_integer', 'number_decimal', 'number_float', 'content_taxonomy'),
       'multiple values' => CONTENT_HANDLE_MODULE,
       'callbacks' => array(
         'default value' => CONTENT_CALLBACK_DEFAULT,
       ),
     ),
-    'select_or_other_sort' => array(
-      'label' => t('Select (or other) drag and drop lists'),
-      'field types' => array('text', 'number_integer', 'number_decimal', 'number_float'),
-      'multiple values' => CONTENT_HANDLE_CORE,
-      'callbacks' => array(
-        'default value' => CONTENT_CALLBACK_DEFAULT,
-      ),
-    ),
     'select_or_other_buttons' => array(
       'label' => t('Select (or other) check boxes/radio buttons'),
-      'field types' => array('text', 'number_integer', 'number_decimal', 'number_float'),
+      'field types' => array('text', 'number_integer', 'number_decimal', 'number_float', 'content_taxonomy'),
       'multiple values' => CONTENT_HANDLE_MODULE,
       'callbacks' => array(
         'default value' => CONTENT_CALLBACK_DEFAULT,
@@ -312,45 +280,28 @@ function select_or_other_widget_info() {
  * This is a CCK hook.
  */
 function select_or_other_widget(&$form, &$form_state, $field, $items, $delta = NULL) {
-
-  $options = array();
-
-  // Create options - similar to code from content_allowed_values().
-  $list = explode("\n", $field['widget']['available_options']);
-  $list = array_map('trim', $list);
-  $list = array_filter($list, 'strlen');
-  foreach ($list as $opt) {
-    // Sanitize the user input with a permissive filter.
-    $opt = content_filter_xss($opt);
-    if (strpos($opt, '|') !== FALSE) {
-      list($key, $value) = explode('|', $opt);
-      $options[$key] = (isset($value) && $value !=='') ? $value : $key;
-    }
-    else {
-      $options[$opt] = $opt;
-    }
-  }
-
+  $options = content_taxonomy_allowed_values($field);
   // Add a 'none' option for non-required single selects, sort selects, and radios
   if (!$field['required']) {
     if (($field['widget']['type'] == 'select_or_other_buttons' && !$field['multiple'])
-      || ($field['widget']['type'] == 'select_or_other' && !$field['multiple'])
-      || ($field['widget']['type'] == 'select_or_other_sort')) {
+      || ($field['widget']['type'] == 'select_or_other' && !$field['multiple'])) {
       $options = array('' => theme('select_or_other_none', $field)) + $options;
     }
   }
 
   // Construct the element.
   $element = array(
+    //'#type' => ($field['widget']['type'] == 'content_taxonomy_select') ? 'optionwidgets_select' : 'optionwidgets_buttons', 
+    '#default_value' => !empty($items) ? $items : array(),
     '#type' => 'select_or_other',
     '#other' => $field['widget']['other'],
-    '#default_value' => isset($items[$delta]) ? $items[$delta] : NULL,
+    //'#default_value' => isset($items[$delta]) ? $items[$delta] : NULL,
     '#options' => $options,
     '#description' => $field['widget']['description'],
     '#multiple' => $field['multiple'],
     '#required' => $field['required'],
-    //'#other_delimiter' => $field['widget']['other_delimiter'] == 'FALSE' ? FALSE : $field['widget']['other_delimiter'],
-    '#other_delimiter' => FALSE,
+    '#other_delimiter' => $field['widget']['other_delimiter'] == 'FALSE' ? FALSE : $field['widget']['other_delimiter'],
+    //'#other_delimiter' => FALSE,
     '#other_unknown_defaults' => $field['widget']['other_unknown_defaults'],
     '#element_validate' => array('select_or_other_cck_validate'),
     '#cck_widget' => $field['widget']['type'],
@@ -360,13 +311,7 @@ function select_or_other_widget(&$form, &$form_state, $field, $items, $delta = N
   switch($field['widget']['type']) {
     case 'select_or_other':
       $element['#select_type'] = 'select';
-      break;
-
-    case 'select_or_other_sort':
-      $element['#select_type'] = 'select';
-      // Also disable multiples for this select type.
-      $element['#multiple'] = FALSE;
-      break;
+     break;
 
     case 'select_or_other_buttons':
       $element['#select_type'] = $field['multiple'] ? 'checkboxes' : 'radios';
@@ -393,38 +338,33 @@ function select_or_other_widget_settings($op, $widget) {
   switch ($op) {
     case 'form':
       $form = array();
-
-      $form['available_options'] = array(
-        '#type' => 'textarea',
-        '#title' => t('Available options'),
-        '#description' => t('A list of values that are, by default, available for selection. Enter one value per line, in the format key|label. The key is the value that will be stored in the database, and the label is what will be displayed to the user.  This is not the same as <em>allowed values</em> (below) which will also restrict what a user can type into the <em>other</em> textfield.'),
-        '#default_value' => isset($widget['available_options']) ? $widget['available_options'] : '',
+//content cck settings.
+      $form['settings'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('Settings for Options'),
+        '#collapsible' => TRUE,
+        '#weight' => 10,
       );
-      $form['other'] = array(
-        '#type' => 'textfield',
-        '#title' => t('<em>Other</em> option'),
-        '#description' => t('Label for the option that the user will choose when they want to supply an <em>other</em> value.'),
-        '#default_value' => isset($widget['other']) ? $widget['other'] : t('Other'),
-        '#required' => TRUE,
+      $form['settings']['show_depth'] = array(
+        '#type' => 'checkbox', 
+        '#title' => t('Indent child terms with \' - \' signs'),
+        '#default_value' => is_numeric($widget['show_depth']) ? $widget['show_depth'] : 1,
+        '#description' => t('If this option is checked, a hierarchy gets visualized by indenting child terms, otherwise it\'s a flat list'),
       );
-      $form['other_unknown_defaults'] = array(
+      $form['settings']['group_parent'] = array(
+        '#title' => t('Parent term for OptGroups in select fields'),
         '#type' => 'select',
-        '#title' => t('<em>Other</em> value as default value'),
-        '#description' => t("If any incoming default values do not appear in <em>available options</em> (i.e. set as <em>other</em> values), what should happen?"),
-        '#options' => array(
-          'other' => t('Add the values to the other textfield.'),
-          'append' => t('Append the values to the options'),
-          'ignore' => t('Ignore the values'),
-        ),
-        '#default_value' => isset($widget['other_unknown_defaults']) ? $widget['other_unknown_defaults'] : 'other',
-        '#required' => TRUE,
+        '#default_value' => isset($widget['group_parent']) ? $widget['group_parent'] : 0,
+        '#options' => _content_taxonomy_get_all_terms(),
+        '#description' => t('This settings applies only for select fields. Select a parent term containg the grouping terms. Grouping terms should be parents of the selected terms (from the Global Settings).'),
       );
+
       /*
       There are design issues with saving multiple other values with some CCK widgets - this needs a rethink.
 
       $form['other_delimiter'] = array(
         '#type' => 'textfield',
-        '#title' => t('Other delimiter'),
+        '#title' => t('"Other" delimiter'),
         '#description' => t("Delimiter string to delimit multiple 'other' values into the <em>other</em> textfield.  If you enter <em>FALSE</em> only the last value will be used."),
         '#default_value' => isset($widget['other_delimiter']) ? $widget['other_delimiter'] : ', ',
         '#required' => TRUE,
@@ -434,7 +374,7 @@ function select_or_other_widget_settings($op, $widget) {
       return $form;
 
     case 'save':
-      return array('available_options', 'other', 'other_unknown_defaults', /*'other_delimiter'*/);
+      return array('available_options', 'other', 'other_unknown_defaults', 'group_parent', 'show_depth', 'other_delimiter');
   }
 }
 
@@ -443,26 +383,30 @@ function select_or_other_widget_settings($op, $widget) {
  */
 function select_or_other_cck_validate($element, &$form_state) {
   $other_selected = FALSE;
-
+  //if "other is selected" and multiple items are set
   if (is_array($element['select']['#value']) && in_array('select_or_other', $element['select']['#value'])) {
     // This is a multiselect. assoc arrays
     $other_selected = TRUE;
-    $value = $element['select']['#value'];
-    unset($value['select_or_other']);
-    $value[$element['other']['#value']] = $element['other']['#value'];
+    $val = $element['select']['#value'];
+    unset($val['select_or_other']);
   }
+  //only if cck settings are set to 1 item and other is selected.
   else if (is_string($element['select']['#value']) && $element['select']['#value'] == 'select_or_other') {
     // This is a single select.
     $other_selected = TRUE;
-    $value = $element['other']['#value'];
+    $val['value'] = $element['other']['#value'];
   }
+  //other is not selected
   else {
-    $value = $element['select']['#value'];
+    $val = $element['select']['#value'];
   }
+
+  // Validation for other field
   if ($other_selected && !$element['other']['#value'] && $form_state['values']['form_id'] != 'content_field_edit_form') {
     form_error($element['other'], t('%name: @title is required', array('%name' => t($element['select']['#title']), '@title' => $element['#other'])));
   }
-  if (isset($value)) {
+
+  if (isset($val) || isset($value)) {
     if (in_array($element['#cck_widget'], array('select_or_other', 'select_or_other_buttons'))) {
       // Filter out 'none' value (if present, will always be in key 0)
       if (isset($items[0]['value']) && $items[0]['value'] === '') {
@@ -471,18 +415,58 @@ function select_or_other_cck_validate($element, &$form_state) {
       if ($element['#multiple'] >= 2 && count($value) > $element['#multiple']) {
         form_error($element['select'], t('%name: this field cannot hold more than @count values.', array('%name' => t($element['select']['#title']), '@count' => $element['#multiple'])));
       }
-      $delta = 0;
-      $values = array();
-      foreach ((array)$value as $v) {
-        $values[$delta++]['value'] = $v;
+      //check if other was selected
+      if ($other_selected) {
+	$value1 = $element['other']['#value'];
+
+	//this is stuff stolen from content_taxonomy_autocomplete
+	$field_name = $element['#field_name'];
+	$field = content_fields($field_name, $element['#type_name']);
+	$field_key  = $element['#columns'][0];
+
+	//if the element parents array contains the field key, we have to remove it
+	//because otherwise form_set_value won't work. (still the question why is it in)
+	if ($element['#parents'][count($element['#parents'])-1] == $field_key) {
+	  array_pop($element['#parents']);
+	  array_pop($element['#array_parents']);
+	}
+	
+	//$value = $element['#value'];
+      
+	$extracted_ids = select_or_other_tags_get_tids($value1, $field['vid'], content_taxonomy_field_get_parent($field), $field['widget']['extra_parent']);
+
+	if (!$field['multiple'] && count(select_or_other_split_tags($value1, $field['vid'])) > 1) {
+	  form_set_error($field['field_name'] .'][value', t('You can provide only one value'));
+	  return;
+	}
+	else if (($field['multiple'] >= 2) && (count(select_or_other_split_tags($value1, $field['vid'])) > $field['multiple'])) {
+	  form_set_error($field['field_name'] .'][value', t('%name: this field cannot hold more than @count values.', array('%name' => t($field['widget']['label']), '@count' => $field['multiple'])));
+	}
+	if ($field['widget']['new_terms'] == 'deny') {
+	  if (is_array($extracted_ids['non_existing_terms'])) {
+	    form_set_error($field['field_name'] .'][value', t('New tags are not allowed'));
+	    return;
+	  }
+	}
+	
+	$values1 = select_or_other_form2data($extracted_ids, $field, $element);
+
+	//add on the regular check items
+	foreach ((array)$val as $v) {
+	  $values1[]['value'] = $v;
+	}
+      }
+      else {
+	//create a $values varible it likes.
+	$delta = 0;
+	$values1 = array();
+	foreach ((array)$val as $v) {
+	  $values1[$delta++]['value'] = $v;
+	}
       }
-      $value = $values;
-    }
-    else if ($element['#cck_widget'] == 'select_or_other_sort') {
-      $value = array('value' => $value);
     }
-    form_set_value($element, $value, $form_state);
-    $form_state['clicked_button']['#post'][$element['#name']] = $value;  // Is this something we should do?
+    form_set_value($element, $values1, $form_state);
+    $form_state['clicked_button']['#post'][$element['#name']] = $values1;  // Is this something we should do?
   }
   return $element;
 }
@@ -497,9 +481,116 @@ function theme_select_or_other_none($field) {
     case 'select_or_other_buttons':
       return t('N/A');
     case 'select_or_other':
-    case 'select_or_other_sort':
-      return t('- None -');
     default :
       return '';
   }
 }
+
+//everything below this line is swiped form content_taxonomy_autocomplete
+
+/**
+ * Helper function to transpose the values returned by submitting the content_taxonomy_autcomplete
+ * to the format to be stored in the field
+ */
+function select_or_other_form2data($extracted_ids, $field, $element) {
+  $existing_tids = is_array($extracted_ids['existing_tids']) ? $extracted_ids['existing_tids'] : array();
+  $new_tids = array();
+  if (is_array($extracted_ids['non_existing_terms'])) {
+    if ($field['widget']['extra_parent']) {
+      $new_tids = select_or_other_insert_tags($extracted_ids['non_existing_terms'], $field['widget']['extra_parent']);
+    } 
+    else {
+      $new_tids = select_or_other_insert_tags($extracted_ids['non_existing_terms'], content_taxonomy_field_get_parent($field));          
+    }
+  }
+  return content_transpose_array_rows_cols(array($element['#columns'][0] => array_merge($existing_tids, $new_tids)));
+
+}
+
+
+/**
+ * Insert new tags
+ *
+ * @param $nid the node id
+ * @param $terms an array of all <strong>nonexisting</strong> terms.
+ * @return an array of newly inserted term ids
+ */
+function select_or_other_insert_tags($terms, $parent = NULL) {
+  foreach ($terms as $term) {
+    $edit = array('vid' => $term['vid'], 'name' => $term['name']);
+    if ($parent) $edit['parent'] = $parent;
+    $status = taxonomy_save_term($edit);
+    $saved_terms[$edit['tid']] = $edit['tid'];
+  }
+  return $saved_terms;
+}
+
+
+/**
+ * Helper function to split the tags
+ */
+function select_or_other_split_tags($typed_input) {
+  $regexp = '%(?:^|,\ *)("(?>[^"]*)(?>""[^"]* )*"|(?: [^",]*))%x';
+  preg_match_all($regexp, $typed_input, $matches);
+  return $matches[1];
+}
+
+/**
+ * Get TIDs for freetagging tags
+ *  Free tagging vocabularies do not send their tids in the form,
+ *  so we'll detect them here and process them independently.
+ * @param $typed_input A string containing all comma separated tags. As the user typed it.
+ */
+function select_or_other_tags_get_tids($typed_input, $vid, $parent = 0, $extra_parent = 0) {
+  // This regexp allows the following types of user input:
+  // this, "somecmpany, llc", "and ""this"" w,o.rks", foo bar
+  $typed_terms = select_or_other_split_tags($typed_input);
+
+  foreach ($typed_terms as $typed_term) {
+    // If a user has escaped a term (to demonstrate that it is a group,
+    // or includes a comma or quote character), we remove the escape
+    // formatting so to save the term into the DB as the user intends.
+    $typed_term = trim(str_replace('""', '"', preg_replace('/^"(.*)"$/', '\1', $typed_term)));
+    if ($typed_term == "") { continue; }
+    
+    // See if the term exists in the chosen vocabulary
+    // and return the tid, otherwise, add a new record.
+    $possibilities = taxonomy_get_term_by_name($typed_term);
+
+    $typed_term_tid = NULL; // tid match if any.
+    foreach ($possibilities as $possibility) {
+      if ($possibility->vid == $vid) {
+        if ($parent) {
+          $parents = array();
+          $parents = taxonomy_get_parents($possibility->tid);
+          if (in_array($parent, array_keys($parents)) || in_array($extra_parent, array_keys($parents))) {
+            $result['existing_tids'][$possibility->tid] = $possibility->tid;
+            $typed_term_tid = $possibility->tid;  
+          }
+        }
+        else {
+          $result['existing_tids'][$possibility->tid] = $possibility->tid;
+          $typed_term_tid = $possibility->tid;
+        }
+      }
+    }
+
+    if (!$typed_term_tid) {
+      $result['non_existing_terms'][] = array(
+        'name' => $typed_term,
+        'vid' => $vid,
+      );
+    }
+  }
+
+  return $result;
+}
+
+
+
+
+
+
+
+
+
-- 
1.5.4.3

