Index: modules/field/modules/options/options.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/modules/options/options.module,v
retrieving revision 1.7
diff -u -p -r1.7 options.module
--- modules/field/modules/options/options.module	28 May 2009 16:44:06 -0000	1.7
+++ modules/field/modules/options/options.module	13 Jun 2009 05:25:15 -0000
@@ -44,7 +44,7 @@ function options_field_widget_info() {
   return array(
     'options_select' => array(
       'label' => t('Select list'),
-      'field types' => array('list', 'list_boolean', 'list_text', 'list_number'),
+      'field types' => array('list', 'list_boolean', 'list_text', 'list_number', 'term'),
       'behaviors' => array(
         'multiple values' => FIELD_BEHAVIOR_CUSTOM,
         'default value' => FIELD_BEHAVIOR_DEFAULT,
@@ -52,7 +52,7 @@ function options_field_widget_info() {
     ),
     'options_buttons' => array(
       'label' => t('Check boxes/radio buttons'),
-      'field types' => array('list', 'list_boolean', 'list_text', 'list_number'),
+      'field types' => array('list', 'list_boolean', 'list_text', 'list_number', 'term'),
       'behaviors' => array(
         'multiple values' => FIELD_BEHAVIOR_CUSTOM,
         'default value' => FIELD_BEHAVIOR_DEFAULT,
Index: modules/taxonomy/taxonomy.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.admin.inc,v
retrieving revision 1.54
diff -u -p -r1.54 taxonomy.admin.inc
--- modules/taxonomy/taxonomy.admin.inc	12 Jun 2009 13:59:56 -0000	1.54
+++ modules/taxonomy/taxonomy.admin.inc	13 Jun 2009 05:25:16 -0000
@@ -12,20 +12,15 @@
  * @ingroup forms
  * @see taxonomy_overview_vocabularies_submit()
  * @see theme_taxonomy_overview_vocabularies()
+ * @todo this function displays list of node types where a vocabulary applies. removal of taxonomy_vocabulary_node_type table
+ *  means this has to be done differently.
  */
 function taxonomy_overview_vocabularies() {
   $vocabularies = taxonomy_get_vocabularies();
   $form = array('#tree' => TRUE);
   foreach ($vocabularies as $vocabulary) {
-    $types = array();
-    foreach ($vocabulary->nodes as $type) {
-      $node_type = node_type_get_name($type);
-      $types[] = $node_type ? check_plain($node_type) : check_plain($type);
-    }
     $form[$vocabulary->vid]['#vocabulary'] = $vocabulary;
     $form[$vocabulary->vid]['name'] = array('#markup' => check_plain($vocabulary->name));
-    $form[$vocabulary->vid]['types'] = array('#markup' => implode(', ', $types));
-    $form[$vocabulary->vid]['weight'] = array('#type' => 'weight', '#delta' => 10, '#default_value' => $vocabulary->weight);
     $form[$vocabulary->vid]['edit'] = array('#markup' => l(t('edit vocabulary'), "admin/content/taxonomy/$vocabulary->vid"));
     $form[$vocabulary->vid]['list'] = array('#markup' => l(t('list terms'), "admin/content/taxonomy/$vocabulary->vid/list"));
     $form[$vocabulary->vid]['add'] = array('#markup' => l(t('add terms'), "admin/content/taxonomy/$vocabulary->vid/add"));
@@ -36,9 +31,6 @@ function taxonomy_overview_vocabularies(
   if (count($vocabularies) > 1) {
     $form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
   }
-  elseif (isset($vocabulary)) {
-    unset($form[$vocabulary->vid]['weight']);
-  }
   return $form;
 }
 
@@ -49,8 +41,7 @@ function taxonomy_overview_vocabularies(
  */
 function taxonomy_overview_vocabularies_submit($form, &$form_state) {
   foreach ($form_state['values'] as $vid => $vocabulary) {
-    if (is_numeric($vid) && $form[$vid]['#vocabulary']->weight != $form_state['values'][$vid]['weight']) {
-      $form[$vid]['#vocabulary']->weight = $form_state['values'][$vid]['weight'];
+    if (is_numeric($vid)) {
       taxonomy_vocabulary_save($form[$vid]['#vocabulary']);
     }
   }
@@ -71,11 +62,6 @@ function theme_taxonomy_overview_vocabul
 
       $row = array();
       $row[] = drupal_render($vocabulary['name']);
-      $row[] = drupal_render($vocabulary['types']);
-      if (isset($vocabulary['weight'])) {
-        $vocabulary['weight']['#attributes']['class'] = 'vocabulary-weight';
-        $row[] = drupal_render($vocabulary['weight']);
-      }
       $row[] = drupal_render($vocabulary['edit']);
       $row[] = drupal_render($vocabulary['list']);
       $row[] = drupal_render($vocabulary['add']);
@@ -86,15 +72,23 @@ function theme_taxonomy_overview_vocabul
     $rows[] = array(array('data' => t('No vocabularies available.'), 'colspan' => '5'));
   }
 
-  $header = array(t('Vocabulary name'), t('Content types'));
-  if (isset($form['submit'])) {
-    $header[] = t('Weight');
-    drupal_add_tabledrag('taxonomy', 'order', 'sibling', 'vocabulary-weight');
-  }
+  $header = array(t('Vocabulary name'));
   $header[] = array('data' => t('Operations'), 'colspan' => '3');
   return theme('table', $header, $rows, array('id' => 'taxonomy')) . drupal_render_children($form);
 }
 
+
+/**
+ * Take a user-entered name and make it machine-safe.
+ *
+ * Replace spaces and all unknown characters with underscores and lowercase.
+ *
+ * @TODO get this into common.inc
+ */
+function drupal_system_string($string, $replacement = '_') {
+  return preg_replace('/[^a-z0-9]+/', $replacement, strtolower($string));
+}
+
 /**
  * Display form for adding and editing vocabularies.
  *
@@ -111,13 +105,11 @@ function taxonomy_form_vocabulary(&$form
     'machine_name' => '',
     'description' => '',
     'help' => '',
-    'nodes' => array(),
     'hierarchy' => 0,
     'relations' => 0,
     'tags' => 0,
     'multiple' => 0,
     'required' => 0,
-    'weight' => 0,
   );
   $form['#vocabulary'] = (object) $edit;
   // Check whether we need a deletion confirmation form.
@@ -154,13 +146,28 @@ function taxonomy_form_vocabulary(&$form
     '#default_value' => $edit['description'],
     '#description' => t('Description of the vocabulary; can be used by modules.'),
   );
-  $form['nodes'] = array(
-    '#type' => 'checkboxes',
-    '#title' => t('Content types'),
-    '#default_value' => $edit['nodes'],
-    '#options' => array_map('check_plain', node_type_get_names()),
-    '#description' => t('Select content types to categorize using this vocabulary.'),
-  );
+  if (module_exists('term')) {
+    $edit['nodes'] = array();
+    if (array_key_exists('vid', $edit)) {
+      $instances = array();
+      foreach (field_read_fields(array('field_name' => $edit['machine_name'], 'module' => 'term')) as $field) {
+        if ($field['settings']['vid'] == $edit['vid']) {
+          $fields[] = $field['field_name'];
+          $instances = array_merge(field_read_instances(array('field_name' => $fields)), $instances);
+        }
+      }
+      foreach ($instances as $instance) {
+        $edit['nodes'][] = $instance['bundle'];
+      }
+    }
+    $form['nodes'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Content types'),
+      '#default_value' => $edit['nodes'],
+      '#options' => array_map('check_plain', node_type_get_names()),
+      '#description' => t('Select content types to categorize using this vocabulary.'),
+    );
+  }
   $form['settings'] = array(
     '#type' => 'fieldset',
     '#title' => t('Settings'),
@@ -184,6 +191,8 @@ function taxonomy_form_vocabulary(&$form
     '#default_value' => $edit['required'],
     '#description' => t('At least one term in this vocabulary must be selected when submitting a post.'),
   );
+
+  // @TODO - what?  this *disables* multiple parents, and there's no UI way to turn it on!?!
   // Set the hierarchy to "multiple parents" by default. This simplifies the
   // vocabulary form and standardizes the term form.
   $form['hierarchy'] = array(
@@ -222,7 +231,7 @@ function taxonomy_form_vocabulary_valida
     // Do not allow duplicate machine names.
     $vocabularies = taxonomy_get_vocabularies();
     foreach ($vocabularies as $vocabulary) {
-      if ($machine_name == $vocabulary->machine_name && (!(isset($form_state['values']['vid']) && $vocabulary->vid != $form_state['values']['vid']))) {
+      if ($machine_name == $vocabulary->machine_name && (!(isset($form_state['values']['vid']) && $vocabulary->vid == $form_state['values']['vid']))) {
         form_set_error('machine_name', t('This machine-readable name is already in use by another vocabulary and must be unique.'));
       }
     }
@@ -255,6 +264,36 @@ function taxonomy_form_vocabulary_submit
       watchdog('taxonomy', 'Updated vocabulary %name.', array('%name' => $vocabulary->name), WATCHDOG_NOTICE, l(t('edit'), 'admin/content/taxonomy/' . $vocabulary->vid));
       break;
   }
+  if (module_exists('term')) {
+    if (!field_read_field($vocabulary->machine_name)) {
+      $field = array(
+        'field_name' => $vocabulary->machine_name,
+        'module' => 'term',
+        'type' => 'term',
+        'cardinality' => ($vocabulary->multiple ? FIELD_CARDINALITY_UNLIMITED : 1),
+        'settings' => array(
+          'vid' => $vocabulary->vid,
+        ),
+      );
+      field_create_field($field);
+    }
+    $instance = array(
+      'field_name' => $vocabulary->machine_name,
+      'bundle' => '',
+      'label' => $vocabulary->name,
+      'description' => $vocabulary->description,
+      'required' => $vocabulary->required,
+      'widget' => array(
+        'type' => 'options_select',
+      ),
+    );
+    foreach ($vocabulary->nodes as $node_type) {
+      $instance['bundle'] = $node_type;
+      if (!field_read_instance($vocabulary->machine_name, $node_type)) {
+        field_create_instance($instance);
+      }
+    }
+  }
 
   $form_state['vid'] = $vocabulary->vid;
   $form_state['redirect'] = 'admin/content/taxonomy';
Index: modules/taxonomy/taxonomy.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.module,v
retrieving revision 1.478
diff -u -p -r1.478 taxonomy.module
--- modules/taxonomy/taxonomy.module	12 Jun 2009 13:59:56 -0000	1.478
+++ modules/taxonomy/taxonomy.module	13 Jun 2009 05:25:18 -0000
@@ -258,21 +258,6 @@ function taxonomy_vocabulary_save($vocab
 
   if (!empty($vocabulary->vid) && !empty($vocabulary->name)) {
     $status = drupal_write_record('taxonomy_vocabulary', $vocabulary, 'vid');
-    db_delete('taxonomy_vocabulary_node_type')
-      ->condition('vid', $vocabulary->vid)
-      ->execute();
-
-    if (!empty($vocabulary->nodes)) {
-      $query = db_insert('taxonomy_vocabulary_node_type')
-        ->fields(array('vid', 'type'));
-      foreach ($vocabulary->nodes as $type => $selected) {
-        $query->values(array(
-          'vid' => $vocabulary->vid,
-          'type' => $type,
-        ));
-      }
-      $query->execute();
-    }
     module_invoke_all('taxonomy_vocabulary_update', $vocabulary);
   }
   elseif (empty($vocabulary->vid)) {
@@ -313,9 +298,6 @@ function taxonomy_vocabulary_delete($vid
   db_delete('taxonomy_vocabulary')
     ->condition('vid', $vid)
     ->execute();
-  db_delete('taxonomy_vocabulary_node_type')
-    ->condition('vid', $vid)
-    ->execute();
   $result = db_query('SELECT tid FROM {taxonomy_term_data} WHERE vid = :vid', array(':vid' => $vid))->fetchCol();
   foreach ($result as $tid) {
     taxonomy_term_delete($tid);
@@ -605,6 +587,8 @@ function taxonomy_form_all($free_tags = 
  *
  * @param $type
  *   If set, return only those vocabularies associated with this node type.
+ * @todo in getting rid of the taxonomy_vocabulary_node_type table, the ability to get
+ *   vocabularies by type has gone. no core functions relied on this feature anyway.
  */
 function taxonomy_get_vocabularies($type = NULL) {
   $conditions = !empty($type) ? array('type' => $type) : NULL;
@@ -648,12 +632,10 @@ function taxonomy_form_alter(&$form, $fo
       $terms = $node->taxonomy;
     }
     $query = db_select('taxonomy_vocabulary', 'v');
-    $query->join('taxonomy_vocabulary_node_type', 'n', 'v.vid = n.vid');
     $query->addTag('term_access');
 
     $result = $query
       ->fields('v')
-      ->condition('n.type', $node->type)
       ->orderBy('v.weight')
       ->orderBy('v.name')
       ->execute();
@@ -1246,19 +1228,11 @@ function taxonomy_vocabulary_load_multip
   // we have $vids still to load, or if no $vids were passed.
   if ($vids || !$passed_vids) {
     $query = db_select('taxonomy_vocabulary', 'v');
-    $query->addField('n', 'type');
     $query
       ->fields('v')
       ->orderBy('v.weight')
       ->orderBy('v.name');
 
-    if (!empty($type)) {
-      $query->leftJoin('taxonomy_vocabulary_node_type', 'n', 'v.vid = n.vid AND n.type  = :type', array(':type' => $type));
-    }
-    else {
-      $query->leftJoin('taxonomy_vocabulary_node_type', 'n', 'v.vid = n.vid');
-    }
-
     // If the $vids array is populated, add those to the query.
     if ($vids) {
       $query->condition('v.vid', $vids, 'IN');
Index: modules/taxonomy/term.info
===================================================================
RCS file: modules/taxonomy/term.info
diff -N modules/taxonomy/term.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/taxonomy/term.info	13 Jun 2009 05:25:18 -0000
@@ -0,0 +1,6 @@
+; $Id$
+name = Term
+description = Defines taxonomy term field types. Use with Options to create selection lists.
+package = Core - fields
+core = 7.x
+files[]=term.module
Index: modules/taxonomy/term.module
===================================================================
RCS file: modules/taxonomy/term.module
diff -N modules/taxonomy/term.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/taxonomy/term.module	13 Jun 2009 05:25:18 -0000
@@ -0,0 +1,135 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Defines term field types that can be used with the Options module.
+ */
+
+/**
+ * Implement hook_theme().
+ */
+function term_theme() {
+  return array(
+    'field_formatter_term_default' => array(
+      'arguments' => array('element' => NULL),
+    ),
+  );
+}
+
+/**
+ * Implement hook_field_info().
+ */
+function term_field_info() {
+  return array(
+    'term' => array(
+      'label' => t('Term'),
+      'description' => t('This field stores keys from key/value terms of allowed numbers where the stored numeric key has significance and must be preserved, i.e. \'Lifetime in days\': 1|1 day, 7|1 week, 31|1 month.'),
+      'settings' => array('allowed_values_function' => ''),
+      'default_widget' => 'options_select',
+      'default_formatter' => 'term_default',
+      'settings' => array('vid' => 0),
+    ),
+  );
+}
+
+/**
+ * Implement hook_field_schema().
+ */
+function term_field_schema($field) {
+  $columns = array(
+    'value' => array(
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => FALSE,
+    ),
+  );
+  return array(
+    'columns' => $columns,
+    'indexes' => array(
+      'value' => array('value'),
+    ),
+  );
+}
+
+/**
+ * Implement hook_field_validate().
+ *
+ * Possible error codes:
+ * - 'term_illegal_value': The value is not part of the list of allowed values.
+ */
+function term_field_validate($obj_type, $object, $field, $instance, $items, &$errors) {
+  $allowed_values = term_allowed_values($field);
+  foreach ($items as $delta => $item) {
+    if (!empty($item['value'])) {
+      if (count($allowed_values) && !array_key_exists($item['value'], $allowed_values)) {
+        $errors[$field['field_name']][$delta][] = array(
+          'error' => 'term_illegal_value',
+          'message' => t('%name: illegal value.', array('%name' => t($instance['label']))),
+        );
+      }
+    }
+  }
+}
+
+/**
+ * Implement hook_field_is_empty().
+ */
+function term_field_is_empty($item, $field) {
+  if (empty($item['value']) && (string)$item['value'] !== '0') {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Implement hook_field_formatter_info().
+ */
+function term_field_formatter_info() {
+  return array(
+    'term_default' => array(
+      'label' => t('Default'),
+      'field types' => array('term'),
+      'behaviors' => array(
+        'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+      ),
+    ),
+  );
+}
+
+/**
+ * Theme function for 'default' term field formatter.
+ */
+function theme_field_formatter_term_default($element) {
+  $field = field_info_field($element['#field_name']);
+  if (($allowed_values = term_allowed_values($field)) && isset($allowed_values[$element['#item']['value']])) {
+    $term = taxonomy_term_load($element['#item']['value']);
+    return l($term->name, taxonomy_term_path($term));
+  }
+  // If no match was found in allowed values, fall back to the key.
+  return 'invalid - '. $element['#item']['value'];
+}
+
+/**
+ *  Create an array of the allowed values for this field.
+ *
+ *  Call the allowed_values_function to retrieve the allowed
+ *  values array.
+ *
+ *  This function should imitate the features of _taxonomy_term_select
+ *
+ *  TODO Rework this to create a method of selecting plugable allowed values terms
+ *  TODO deal with excluded tids
+ *
+ */
+function term_allowed_values($field) {
+  $tree = taxonomy_get_tree($field['settings']['vid']);
+  $options = array();
+
+  if ($tree) {
+    foreach ($tree as $term) {
+      $options[$term->tid] = str_repeat('-', $term->depth) . $term->name;
+    }
+  }
+  return $options;
+}
