diff -Nurp author_taxonomy/author_taxonomy.info author_taxonomy/author_taxonomy.info
--- author_taxonomy/author_taxonomy.info	2009-03-17 11:20:03.000000000 -0700
+++ author_taxonomy/author_taxonomy.info	2012-02-01 14:20:38.000000000 -0800
@@ -3,10 +3,3 @@ name = Author Taxonomy
 description = Identifies authors using terms from a vocabulary. Supports multiple authors.
 core = 6.x
 dependencies[] = taxonomy
-
-; Information added by drupal.org packaging script on 2009-03-17
-version = "6.x-1.8"
-core = "6.x"
-project = "author_taxonomy"
-datestamp = "1237314003"
-
diff -Nurp author_taxonomy/author_taxonomy.install author_taxonomy/author_taxonomy.install
--- author_taxonomy/author_taxonomy.install	2009-01-23 15:40:20.000000000 -0800
+++ author_taxonomy/author_taxonomy.install	2012-02-01 14:20:38.000000000 -0800
@@ -10,13 +10,58 @@ function author_taxonomy_schema() {
     'primary_key' => array('tid'),
     'indexes' => array('uid' => array('uid')),
   );
-  
+
+  // This table keeps a list of nodes, the terms associated with each one, and the 
+  // the weight of each term, so that they have an order
+  // nid -- the node id, of the article or paper
+  // vid -- the node version id of the article or paper (note the taxonomy module also keeps terms
+  //        by both nid and vid)
+  // tid -- the term id or taxonomy id, in this case an author
+  // weight -- an integer weight to allow ordering of all the author's associated with the
+  //           article; in some settings (academia) the order of author listings is important
+  $schema['author_taxonomy_term_order'] = array(
+    'fields' => array(
+      'nid'    => array('type' => 'int', 
+			'unsigned' => TRUE, 
+			'not null' => TRUE, 
+			'default' => 0,
+			'description' => 'The Node ID this term is related to'),
+      'vid'    => array('type' => 'int', 
+			'unsigned' => TRUE, 
+			'not null' => TRUE, 
+			'default' => 0,
+			'description' => 'The Node Version ID this term is related to'),
+      'tid'    => array('type' => 'int', 
+			'unsigned' => TRUE, 
+			'not null' => TRUE, 
+			'default' => 0,
+			'description' => 'The taxonomy term id'),
+      'weight' => array('type' => 'int',
+			'unsigned' => FALSE,
+			'not null' => TRUE,
+			'default' => 0,
+			'description' => 'The weight for ordering, of this term for this node id and version id' ),
+    ),
+ 
+    'primary_key' => array('nid', 'vid'),
+    // Most of the time we will look up by nid and vid to get weight, with an "order by weight"
+    'indexes' => array( 'nid' => array('nid'),
+			'vid' => array('vid'),
+			'weight' => array('weight') ),
+  );
+
   return $schema;
 }
 
 
 function author_taxonomy_install() {
   drupal_install_schema('author_taxonomy');
+
+  // Make sure our module weight is higher than the taxonomy module.  If you don't do this, our _alter_form 
+  // stuff can appear on every node edit page, and not just the types associated with the taxonomy.
+  $weight = (int) db_result(db_query("SELECT weight FROM {system} WHERE name = 'taxonomy'"));
+  db_query("UPDATE {system} SET weight = %d WHERE name = 'author_taxonomy'", $weight + 1);
+
   drupal_set_message(t('The Author Taxonomy module must have a taxonomy assigned to function properly.<br> Please visit the <a href="!url">Author Taxonomy settings page</a> and assign a taxonomy.', array('!url' => url('admin/settings/author_taxonomy'))), 'error');
 }
 
@@ -35,4 +80,35 @@ function author_taxonomy_update_6101() {
   $ret = array();
   $ret = drupal_install_schema('author_taxonomy');
   return $ret;
-}
\ No newline at end of file
+}
+
+
+// This update is for the user defined order feature, which includes a new table
+// and a dependency on having a higher module weight.
+function author_taxonomy_update_6102() {
+  $ret = array();
+  $ret = drupal_install_schema('author_taxonomy');
+  $weight = (int) db_result(db_query("SELECT weight FROM {system} WHERE name = 'taxonomy'"));
+  db_query("UPDATE {system} SET weight = %d WHERE name = 'author_taxonomy'", $weight + 1);
+  return $ret;
+}
+
+
+// Fix renamed author_taxonomy_link_authors variable options.
+function author_taxonomy_update_6103() {
+  $author_links = variable_get('author_taxonomy_link_authors', 1);
+  switch ($author_links) {
+    case 0:
+      variable_set('author_taxonomy_link_authors', 'none');
+      break;
+    case 1:
+      variable_set('author_taxonomy_link_authors', 'taxonomy');
+      break;
+    case 2:
+      variable_set('author_taxonomy_link_authors', 'profile');
+      break;
+  }
+
+  // Must return an array.
+  return array();
+}
diff -Nurp author_taxonomy/author_taxonomy.module author_taxonomy/author_taxonomy.module
--- author_taxonomy/author_taxonomy.module	2009-03-17 11:05:49.000000000 -0700
+++ author_taxonomy/author_taxonomy.module	2012-03-28 08:08:26.000000000 -0700
@@ -1,5 +1,5 @@
 <?php
-// $Id: author_taxonomy.module,v 1.3.2.9 2009/03/17 18:05:49 robbiesternenberg Exp $
+// $Id: author_taxonomy.module,v 1.3.2.10 2009/06/09 16:54:30 toddnienkerk Exp $
 
 /**
  * @file
@@ -56,67 +56,6 @@ function author_taxonomy_menu() {
   return $items;
 }
 
-function author_taxonomy_delete_links() {
-  if (arg(4)) {
-    $tid = arg(4);
-    $term = taxonomy_get_term($tid);
-    $form = array();
-    
-    $form['tid'] = array('#type' => 'value',
-      '#value' => $tid,
-    );
-  
-    return confirm_form(
-              $form,
-              t('Are you sure you want to delete the link to term %title?', array('%title' => $term->name)),
-              'admin/settings/author_taxonomy/list_links',
-              t('This action cannot be undone.'),
-              t('Delete'),
-              t('Cancel')
-            );
-  } else {
-    drupal_goto('admin/settings/author_taxonomy/list_links');
-  }
-}
-
-function author_taxonomy_delete_links_submit($form, &$form_state) {
-  $term = taxonomy_get_term($form_state['values']['tid']);
-  
-  db_query('DELETE FROM {author_taxonomy_term_link} WHERE tid = %d', $term->tid);
-  drupal_set_message(t('Deleted link to term %name.', array('%name' => $term->name)));
-  $form_state['redirect'] = 'admin/settings/author_taxonomy/list_links';
-  
-  return;
-}
-
-
-function author_taxonomy_list_links() {
-  $header = array(t('Term'), t('User'), array('data' => t('Operations'), 'colspan' => '2'));
-  $rows = array();
-  $pager_num = 0;
-  $sql = 'SELECT * FROM {author_taxonomy_term_link}';
-  $output = '';
-  
-  $result = pager_query($sql, 10, $pager_num, NULL);
-    
-  while($link = db_fetch_object($result)) {
-    $row = array();
-    $user = user_load($link->uid);
-    $term = taxonomy_get_term($link->tid);
-  
-    $row[] = check_plain($term->name);
-    $row[] = l($user->name, 'user/' . $user->uid, array('title' => t('Go to @author\'s profile page', array('@author' => $user->name))));
-    $row[] = l('edit term', 'admin/content/taxonomy/edit/term/' . $term->tid, array('title' => t('edit term')));
-    $row[] = l('delete link', 'admin/settings/author_taxonomy/delete/' . $term->tid);
-  
-    $rows[] = array('data' => $row);
-  }
-  
-  $output .= theme('table', $header, $rows);
-  $output .= theme('pager', NULL, 10, $pager_num);
-  return $output;
-}
-
 
 /**
  * Provides the settings options for the module.
@@ -145,9 +84,9 @@ function author_taxonomy_admin_settings(
   
   // Make list of available date formats
   $date_formats = array(
-    'small' => 'Short',
+    'small'  => 'Short',
     'medium' => 'Medium',
-    'large' => 'Long',
+    'large'  => 'Long',
     'custom' => 'Custom (below)',
   );
 
@@ -201,10 +140,14 @@ function author_taxonomy_admin_settings(
   );
     $form['linking']['author_taxonomy_link_authors'] = array(
       '#type' => 'radios',
-      '#default_value' => variable_get('author_taxonomy_link_authors', 1),
-      '#options' => array(t('Display authors\' names without links'), t('Display authors\' names as links to their taxonomy pages'), t('Display authors\' names as links to their user profile pages')  ),
+      '#default_value' => variable_get('author_taxonomy_link_authors', 'taxonomy'),
+      '#options' => array(
+        'none'     => t('Display authors\' names without links'),
+        'taxonomy' => t('Display authors\' names as links to their taxonomy pages'),
+        'profile'  => t('Display authors\' names as links to their user profile pages'),
+      ),
     );  
-  
+
   $form['timestamp'] = array(
     '#type' => 'fieldset',
     '#title' => t('Timestamp display options'),
@@ -237,6 +180,13 @@ function author_taxonomy_admin_settings(
       '#size' => 20,
     );
 
+    $form['author_taxonomy_user_defined_order'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('User Defined Order'),
+      '#default_value' => variable_get('author_taxonomy_user_defined_order', TRUE),
+      '#description' => t('Checking this box will allow order of the author tags to be set when editting.  The taxonomy being used must have tags enabled.'),
+    );
+
   $form['#submit'][] = 'author_taxonomy_admin_settings_submit';
 
   return system_settings_form($form);
@@ -250,8 +200,72 @@ function author_taxonomy_admin_settings_
   }
 }
 
+
+function author_taxonomy_delete_links() {
+  if (arg(4)) {
+    $tid = arg(4);
+    $term = taxonomy_get_term($tid);
+    $form = array();
+    
+    $form['tid'] = array('#type' => 'value',
+      '#value' => $tid,
+    );
+  
+    return confirm_form(
+              $form,
+              t('Are you sure you want to delete the link to term %title?', array('%title' => $term->name)),
+              'admin/settings/author_taxonomy/list_links',
+              t('This action cannot be undone.'),
+              t('Delete'),
+              t('Cancel')
+            );
+  } else {
+    drupal_goto('admin/settings/author_taxonomy/list_links');
+  }
+}
+
+
+function author_taxonomy_delete_links_submit($form, &$form_state) {
+  $term = taxonomy_get_term($form_state['values']['tid']);
+  
+  db_query('DELETE FROM {author_taxonomy_term_link} WHERE tid = %d', $term->tid);
+  drupal_set_message(t('Deleted link to term %name.', array('%name' => $term->name)));
+  $form_state['redirect'] = 'admin/settings/author_taxonomy/list_links';
+  
+  return;
+}
+
+
+function author_taxonomy_list_links() {
+  $header = array(t('Term'), t('User'), array('data' => t('Operations'), 'colspan' => '2'));
+  $rows = array();
+  $pager_num = 0;
+  $sql = 'SELECT * FROM {author_taxonomy_term_link}';
+  $output = '';
+  
+  $result = pager_query($sql, 10, $pager_num, NULL);
+    
+  while($link = db_fetch_object($result)) {
+    $row = array();
+    $user = user_load($link->uid);
+    $term = taxonomy_get_term($link->tid);
+  
+    $row[] = check_plain($term->name);
+    $row[] = l($user->name, 'user/' . $user->uid, array('title' => t('Go to @author\'s profile page', array('@author' => $user->name))));
+    $row[] = l('edit term', 'admin/content/taxonomy/edit/term/' . $term->tid, array('title' => t('edit term')));
+    $row[] = l('delete link', 'admin/settings/author_taxonomy/delete/' . $term->tid);
+  
+    $rows[] = array('data' => $row);
+  }
+  
+  $output .= theme('table', $header, $rows);
+  $output .= theme('pager', NULL, 10, $pager_num);
+  return $output;
+}
+
+
 /**
- * Implementation of hook_requirements
+ * Implementation of hook_requirements().
  */
 function author_taxonomy_requirements($phase) {
   $requirements = array();
@@ -263,7 +277,7 @@ function author_taxonomy_requirements($p
         'title' => t('Author Taxonomy'),
         'value' => t('Taxonomy not set'),
         'severity' => REQUIREMENT_ERROR,
-        'description' => t('The Author Taxonomy module must have a taxonomy assigned to function properly.<br> Please visit the <a href="!url">Author Taxonomy settings page</a> and assign a taxonomy.', array('!url' => url('admin/settings/author_taxonomy'))),
+        'description' => t('The Author Taxonomy module must have a taxonomy assigned to function properly. Please visit the <a href="@url">Author Taxonomy settings page</a> and assign a taxonomy.', array('@url' => url('admin/settings/author_taxonomy'))),
       );
     }
   }
@@ -274,49 +288,8 @@ function author_taxonomy_requirements($p
 
 
 /**
- * Creates array of authors' names and prepares output for the theme functions.
- */
-function author_taxonomy_output($node) {
-  $author_tids = taxonomy_node_get_terms_by_vocabulary($node, variable_get('author_taxonomy_vocab', 0));
-  $author_names = array();
-  $author_links = variable_get('author_taxonomy_link_authors', 1);
-
-  if (!empty($author_tids)) {
-    foreach ($author_tids as $tid => $term) {
-      switch ($author_links) {
-        case 1:
-          // links to taxonomy pages
-          $author_names[] = l($term->name, taxonomy_term_path($term), array('title' => t('See all stories by @author', array('@author' => $term->name))));
-          break;
-        case 2:
-          // links to user profile pages
-          $uid = FALSE;
-          $uid = db_result(db_query('SELECT uid FROM {author_taxonomy_term_link} WHERE tid = %d', $tid));
-          
-          if ($uid) {
-            $name = l($term->name, 'user/' . $uid, array('title' => t('Go to @author\'s profile page', array('@author' => $term->name))));
-          } else {
-            $name = $term->name;
-          }
-          
-          $author_names[] = $name;
-          break;
-        default:
-          // display authors' names without links
-          $author_names[] = $term->name;
-      }
-    }
-  }
-
-  $show_timestamp = variable_get('author_taxonomy_timestamp_display', TRUE);
-  $replace_submitted = variable_get('author_taxonomy_replace_submitted', TRUE);
-
-  return theme('author_taxonomy_output', $node, $author_names, $show_timestamp, $replace_submitted);
-}
-
-/**
  * Implementation of hook_user().
- * Deletes entries from the db if a user is deleted
+ * Deletes entries from the DB if a user is deleted.
  */
 function author_taxonomy_user($op, &$edit, &$account, $category = NULL) {
   if ($op == 'delete') {
@@ -330,19 +303,47 @@ function author_taxonomy_user($op, &$edi
  * Implementation of hook_nodeapi().
  */
 function author_taxonomy_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
+
   switch ($op) {
 
-    case 'presave' :
-      // Is "overwrite author" option enabled?
-      $overwrite_author = variable_get('author_taxonomy_overwrite_author', FALSE);
+  case 'presave' :
+    $vid = variable_get('author_taxonomy_vocab', 0);
+    if ( variable_get('author_taxonomy_user_defined_order', FALSE ) && 
+         (isset($node->taxonomy['tags'])) &&
+         (isset($node->taxonomy['tags'][$vid])) ) {
+      // This code fixes up the $node->taxonomy['tags'] to be as the taxonomy
+      // module expects it; the ordered author stuff puts it in an expanded 
+      // array with more levels, which is copied for this module's use to $node->author_taxonomy['ordered_tags']
+      //$node->taxonomy['ordered_tags'] = $node->taxonomy['tags'];
+      $node->author_taxonomy['ordered_tags'] = $node->taxonomy['tags'];
+      
+      unset( $node->taxonomy['tags'][$vid] );
+      foreach ( $node->author_taxonomy['ordered_tags'][$vid] as $author_and_weight ) {
+        if ( $author_and_weight['title'] != '' ) {
+          $comma_delimited_terms = $comma_delimited_terms.", ".$author_and_weight['title'] ;
+        }
+      }
+      $node->taxonomy['tags'][$vid] = ltrim($comma_delimited_terms,",");  // ltrim removes extraneous leading comma
+    }
+    
+    // Is "overwrite author" option enabled?
+    $overwrite_author = variable_get('author_taxonomy_overwrite_author', FALSE);
       if ($overwrite_author) {
         taxonomy_node_save($node, $node->taxonomy);
         $author_terms = _author_taxonomy_get_author_terms($node->vid);
 
         if (!empty($author_terms)) {
-          // If there is more than one author term, sort them by weight and alpha
-          if (count($author_terms) > 1) {
-            usort($author_terms, '_author_taxonomy_sort_terms');
+          // If user defined order is on, look up the weights in the table to sort
+          if ( variable_get('author_taxonomy_user_defined_order', FALSE ) ) {
+            // In this case do nothing -- _author_taxonomy_get_author_terms will sort
+            // the array before returning it to us above, see the complecated SQL statement
+            // in that function
+          } else {
+            // no user defined order, use the taxonomy weights
+            // If there is more than one author term, sort them by weight and alpha
+            if (count($author_terms) > 1) {
+              usort($author_terms, '_author_taxonomy_sort_terms');
+            }
           }
 
           // Try to find a match in the users table. Iterate through each author term until a match is found.
@@ -360,6 +361,49 @@ function author_taxonomy_nodeapi(&$node,
       }
       break;
 
+  case 'insert' :
+    $vid = variable_get('author_taxonomy_vocab', 0);
+    if ( variable_get('author_taxonomy_user_defined_order', FALSE ) &&
+        (isset($node->author_taxonomy['ordered_tags'])) &&
+        (isset($node->author_taxonomy['ordered_tags'][$vid])) ) {
+      _author_taxonomy_nodeapi_insert( $node );
+    }
+
+    break;
+    
+  case 'update' :
+    $vid = variable_get('author_taxonomy_vocab', 0);
+    if ( variable_get('author_taxonomy_user_defined_order', FALSE ) &&
+         (isset($node->author_taxonomy['ordered_tags'])) &&
+         (isset($node->author_taxonomy['ordered_tags'][$vid]))  ) {
+      // If this is a pre-existing node being editted, clean it's previous entries
+      $clean_sql = "DELETE FROM author_taxonomy_term_order WHERE nid='%d' AND vid='%d'";
+      db_query( $clean_sql, $node->nid, $node->vid );
+      // Then do the same thing as on an insert
+      _author_taxonomy_nodeapi_insert( $node );
+    }
+
+    break;
+
+  }
+}
+
+function _author_taxonomy_nodeapi_insert( $node )
+{
+  $vid = variable_get('author_taxonomy_vocab', 0);
+  $insert_sql = "INSERT INTO author_taxonomy_term_order (nid, vid, tid, weight) VALUES (%d, %d, %d, %d)";
+
+  foreach ( $node->author_taxonomy['ordered_tags'][$vid] as $author_and_weight ) {
+    // Get the tid of the name -- at this point I think there should always be one, even on
+    // a never-before-seen author ?
+    $tids = taxonomy_get_term_by_name($author_and_weight['title']);
+
+    if ($author_and_weight['title'] != '' && $tids[0]->tid > 0) {
+      db_query( $insert_sql, $node->nid, $node->vid, $tids[0]->tid, $author_and_weight['sort'] );
+	  } else {
+      // I think this case never happens, because the taxonomy module runs before we do
+      // (Should that be assured using module weights ?)
+    }
   }
 }
 
@@ -367,27 +411,120 @@ function author_taxonomy_nodeapi(&$node,
  * Implementation of hook_form_alter()
  */
 function author_taxonomy_form_alter(&$form, $form_state, $form_id) {
-  // make sure this is a 'node' form first
-  if ( isset($form['type']) && isset($form['#node']) && ($form['type']['#value'] .'_node_form' == $form_id) )
-  {
-    global $user;
-  
+
+  // Make sure this is a 'node' form 
+  if ( isset($form['type']) && ($form_id == $form['type']['#value'] .'_node_form') )
+    {
+    
     $vid = variable_get('author_taxonomy_vocab', 0);
     $taxonomy = taxonomy_vocabulary_load($vid);
-  
-    if ($taxonomy->tags == '1') {
-      if (!$form['taxonomy']['tags'][$vid]['#default_value'] && variable_get('author_taxonomy_auto_add', FALSE)) {
-        $form['taxonomy']['tags'][$vid]['#default_value'] = $user->name;
-      }
+
+    // If the vocabulary used for authors does not apply to this content type, do nothing
+    $cur_content_type = $form['type']['#value'];
+    $valid_flag = (int) db_result(db_query("SELECT COUNT(*) FROM {vocabulary_node_types} WHERE vid = '%d' AND type = '%s'", $vid, $cur_content_type ));
+    if ( $valid_flag == 0 ) {
+      return;
     }
+
+
+    if (variable_get('author_taxonomy_auto_add', FALSE) && 
+        $taxonomy->tags && !empty($form['taxonomy']['tags'][$vid]['#default_value'])) {
+        
+      global $user;
+      $form['taxonomy']['tags'][$vid]['#default_value'] = $user->name;
+    }
+
+
+
+    // For user defined order
+    if ( variable_get('author_taxonomy_user_defined_order', FALSE ) && $taxonomy->tags ) {
+
+      $form['taxonomy']['tags'][$vid]['#tree'] = TRUE ;
+        $form['taxonomy']['tags'][$vid]['#theme'] = 'author_taxonomy_user_defined_order_form';
+        $form['taxonomy']['tags'][$vid]['#description'] = $taxonomy->help;
+        $form['taxonomy']['tags'][$vid]['#type'] = '';  // If you leave the original type in, you will get
+                                                        // just a textfield on the page, must be empty to do 
+                                                        // dragable table
+
+        // Get the pre-existing tags, if any, to pre-populate the array
+        $term_orders = array();
+        if ( $form['nid']['#value'] != '' ) {
+          $nid = $form['nid']['#value'];
+          $nodevid = $form['vid']['#value'];
+
+          $term_order_result = db_query( "SELECT tid, weight FROM author_taxonomy_term_order WHERE nid = '%d' AND vid = '%d' ORDER BY weight", $nid, $nodevid );
+
+          while( $term_order = db_fetch_object( $term_order_result ) ) {
+            $taxonomy_term = taxonomy_get_term( $term_order->tid );
+            $weight = $term_order->weight ;
+            
+            // The purpose of this loop, is so that if for some reason two authors ended up with the same weight,
+            // we still display both of them ( on the next save of the article, they should get different weights )
+            while ( !empty( $term_orders[$weight] ) ) {
+              $weight = $weight + 1;
+            }
+            $term_orders[$weight] = $taxonomy_term->name ;
+
+          }
+
+          // At this point, if term_orders was empty, look for un-ordered terms in the taxonomy and
+          // fill in the array with those, with arbitrary weights.  This will mean that if users turn
+          // on the user_order feature after they have data, they will put in the orders as they edit
+          // nodes.
+          if( count( $term_orders ) == 0 ) {
+            // This query was copied from taxonomy.module
+            $term_order_result = db_query(db_rewrite_sql('SELECT t.tid, t.* FROM {term_data} t INNER JOIN {term_node} r ON r.tid = t.tid WHERE t.vid = %d AND r.vid = %d ORDER BY weight', 't', 'tid'), $vid, $nodevid);
+
+            $weight = 0;
+            while( $term_order = db_fetch_object( $term_order_result ) ) {
+              $taxonomy_term = taxonomy_get_term( $term_order->tid );
+              $weight++;
+              $term_orders[$weight] = $taxonomy_term->name;
+            }
+          }
+
+        }
+
+
+        // Always have five blank fields on the end for adding more authors
+        // (This part will go away when we get the javascript "add more" functionality working)
+        $term_orders[count($term_orders)+1] = '' ;
+        $term_orders[count($term_orders)+1] = '' ;
+        $term_orders[count($term_orders)+1] = '' ;
+        $term_orders[count($term_orders)+1] = '' ;
+        $term_orders[count($term_orders)+1] = '' ;
+
+
+        foreach ($term_orders AS $key => $title) {
+          $form['taxonomy']['tags'][$vid][$key]['title'] = array(
+                                                             '#type' => 'textfield',
+                                                             '#default_value' => $title,
+                                                             '#autocomplete_path' => 'taxonomy/autocomplete/'. $vid );
+          $form['taxonomy']['tags'][$vid][$key]['sort'] = array(
+                                                            '#type' => 'weight',
+                                                            '#delta' => count($term_orders),
+                                                            '#default_value' => $key);
+        }
+
+        //array_push( $form['buttons']['submit']['#submit'], '_author_taxonomy_submit_function' ); // run it first
+        //$form['buttons']['submit']['#submit'][] = '_author_taxonomy_submit_function' ; // run it last
+    }
+
   }
 }
 
+/* Not used currently
+function _author_taxonomy_submit_function(&$form, &$form_state) {
+
+}
+*/
+
 
 /**
  * Implementation of hook_form_alter(), specific to the taxonomy term edit form.
  */
 function author_taxonomy_form_taxonomy_form_term_alter(&$form, &$form_state) {
+  
   if (!$form_state['rebuild'] && ($form['vid']['#value'] == variable_get('author_taxonomy_vocab', 0)) ) {
     $form['author_taxonomy'] = array(
       '#type' => 'fieldset',
@@ -480,7 +617,39 @@ function author_taxonomy_taxonomy($op, $
  *  The term objects for the given node ID.
  */
 function _author_taxonomy_get_author_terms($vid) {
-  $result = db_query('SELECT tid FROM {term_node} WHERE vid = %d', $vid);
+
+  if ( variable_get('author_taxonomy_user_defined_order', FALSE ) ) {
+    // This query should get the terms in the right order, so that they do not have to be
+    // subsequently sorted
+
+    $result = db_query("SELECT tid, weight from author_taxonomy_term_order WHERE vid='%d' ORDER BY weight", $vid );
+    $vocab_vid = variable_get('author_taxonomy_vocab', 0);
+    $tids = array();
+    $author_terms  = array();
+
+    while ($row = db_fetch_array($result)) {
+      $tids[] = $row['tid'];
+    }
+
+    // This can happen if there is no user defined data for the node yet, fall back to the
+    // taxonomy weights
+    if ( count($tids) == 0 ) {
+      $result = db_query('SELECT tid FROM {term_node} WHERE vid = %d', $vid);
+    } else {
+      foreach ($tids as $tid) {
+        $term = taxonomy_get_term($tid);
+        if ($term->vid == $vocab_vid) {
+          $author_terms[] = $term;
+        }
+      }
+
+      return $author_terms;
+    }
+    
+  } else {
+    $result = db_query('SELECT tid FROM {term_node} WHERE vid = %d', $vid);
+  }
+
   $vocab_vid = variable_get('author_taxonomy_vocab', 0);
   $tids = array();
   $author_terms  = array();
@@ -522,34 +691,12 @@ function _author_taxonomy_sort_terms($le
   else {
     $result = strcasecmp($left_term->name, $right_term->name);
   }
-
+  
   return $result;
 }
 
 
 /**
- * Implementation of template_preprocess_node().
- * 
- * Intercept and change value of node's $submitted variable if 
- * "Replace post information provided by your theme" is checked
- */
-function author_taxonomy_preprocess_node(&$variables) {
-  $node = $variables['node'];
-
-  if (theme_get_setting('toggle_node_info_'. $node->type) && variable_get('author_taxonomy_replace_submitted', TRUE)) {
-    $variables['submitted'] = author_taxonomy_output($node);
-  }
-
-  if (variable_get('author_taxonomy_remove_terms', TRUE)) {
-    $variables['taxonomy'] = author_taxonomy_link('taxonomy terms', $node);
-    $variables['terms'] = theme('author_taxonomy_terms', $variables['taxonomy']);
-  }
-
-  return $variables;
-}
-
-
-/**
  * Implementation of hook_link().
  * 
  * This is copied from taxonomy.module's hook_link(). Changes
@@ -631,7 +778,7 @@ function author_taxonomy_autocomplete($s
 
 
 /**
- * Return uid based on string created by autocomplete function
+ * Return uid based on string created by autocomplete function.
  */
 function author_taxonomy_get_uid($string = '') {
   $uid = 0;
@@ -647,10 +794,143 @@ function author_taxonomy_get_uid($string
 
 
 /**
+ * Implementation of hook_token_list().
+ */
+function author_taxonomy_token_list($type = 'all') {
+  switch ($type) {
+    case 'node':
+      $tokens['author taxonomy']['authorTaxonomy'] = t('Displays a list of the submission\'s author(s)');
+      break;
+
+  }
+  return $tokens;
+}
+
+
+/**
+ * Implementation of hook_token_values().
+ * TODO: Check for $object == NULL
+ */
+function author_taxonomy_token_values($type, $object = NULL) {
+  switch ($type) {
+    case 'node':
+      $values['authorTaxonomy'] = author_taxonomy_output($object, 'plain');
+      break;
+
+  }
+  return $values;
+}
+
+
+/*
+ * This hook allows the views api to find the author_taxonomy.views.inc file.
+ */
+function author_taxonomy_views_api() {
+  return array(
+    'api' => 2,
+    'path' => drupal_get_path('module', 'author_taxonomy'),
+  );
+}
+
+
+/**
+ * Implementation of template_preprocess_node().
+ * 
+ * Intercept and change value of node's $submitted variable if 
+ * "Replace post information provided by your theme" is checked
+ */
+function author_taxonomy_preprocess_node(&$variables) {
+  $node = $variables['node'];
+
+  if (theme_get_setting('toggle_node_info_'. $node->type) && variable_get('author_taxonomy_replace_submitted', TRUE)) {
+    $variables['submitted'] = author_taxonomy_output($node);
+  }
+
+  if (variable_get('author_taxonomy_remove_terms', TRUE)) {
+    $variables['taxonomy'] = author_taxonomy_link('taxonomy terms', $node);
+    $variables['terms'] = theme('author_taxonomy_terms', $variables['taxonomy']);
+  }
+
+  return $variables;
+}
+
+
+/**
+ * Creates array of authors' names and prepares output for the theme functions.
+ */
+function author_taxonomy_output($node, $link_option = NULL) {
+  // If we are using user defined order, we have to get the list in the right order.
+  if (variable_get('author_taxonomy_user_defined_order', FALSE)) {
+    $author_tids = _author_taxonomy_get_author_terms($node->vid);
+  }
+  else {
+    $author_tids = taxonomy_node_get_terms_by_vocabulary($node, variable_get('author_taxonomy_vocab', 0));
+  }
+
+
+  if(empty($link_option)) {
+    $link_option = variable_get('author_taxonomy_link_authors', 'taxonomy');
+  }
+
+  $show_timestamp = variable_get('author_taxonomy_timestamp_display', TRUE);
+  $replace_submitted = variable_get('author_taxonomy_replace_submitted', TRUE);
+
+  $output = '';
+  $author_names = array();
+
+
+  if (!empty($author_tids)) {
+    foreach ($author_tids as $tid => $term) {
+      
+      switch ($link_option) {
+
+        // Links to taxonomy pages.
+        case 'taxonomy':
+          $author_names[] = l($term->name, taxonomy_term_path($term), array('title' => t('See all stories by @author', array('@author' => $term->name))));
+          break;
+
+        // Links to user profile pages.
+        case 'profile':
+          $uid = FALSE;
+          $uid = db_result(db_query('SELECT uid FROM {author_taxonomy_term_link} WHERE tid = %d', $tid));
+          
+          if ($uid) {
+            $name = l($term->name, 'user/' . $uid, array('title' => t('Go to @author\'s profile page', array('@author' => $term->name))));
+          } else {
+            $name = $term->name;
+          }
+          
+          $author_names[] = $name;
+          break;
+
+        // Display authors' names without links.
+        // Works for 'none' and 'plain' cases.
+        default:
+          $author_names[] = $term->name;
+          break;
+      }
+    }
+  }
+
+  // Output plain text version of authors' names. Used for some tokens.
+  if ($link_option == 'plain') {
+    return theme('author_taxonomy_authors', $author_names);
+  }
+
+  return theme('author_taxonomy_output', $node, $author_names, $show_timestamp, $replace_submitted);
+}
+
+
+/**
  * Implementation of hook_theme().
  */
 function author_taxonomy_theme($existing, $type, $theme, $path) {
   return array(
+    'author_taxonomy_user_defined_order_form' => array(
+      'arguments' => array(
+        'form' => NULL,
+      ),
+    ),
     'author_taxonomy_output' => array(
       'arguments' => array(
         'node' => NULL,
@@ -673,11 +953,37 @@ function author_taxonomy_theme($existing
       'arguments' => array(
         'taxonomy' => NULL,
       ),
-    ),
+     ),
   );
 }
 
 
+function theme_author_taxonomy_user_defined_order_form($form) {
+  drupal_add_tabledrag('author_taxonomy-sort', 'order', 'sibling', 'sort');
+  //  $header = array('', 'Authors', $form['#description'] );
+  $header = array('', 'Authors', '' );
+
+  foreach (element_children($form) as $key) {
+    // Add class to group weight fields for drag and drop.
+    $form[$key]['sort']['#attributes']['class'] = 'sort';
+    
+    $row = array('');
+    //dpm($form[$key]['name']);
+    $row[] = drupal_render($form[$key]['title']);
+    $row[] = drupal_render($form[$key]['sort']);
+    $rows[] = array('data' => $row, 'class' => 'draggable');
+  }
+
+  $output = theme('table', $header, $rows, array('id' => 'author_taxonomy-sort'));
+  $output .= drupal_render($form);
+
+  // TODO: There is surely a better way to do this, talk to Todd about themeing
+  $output .= '<div class="description">' . $form['#description'] . '</div><p><p>';
+
+  return $output;
+}
+
+
 /**
  * Returns div containing authors and timestamp (themeable).
  */
@@ -717,7 +1023,7 @@ function theme_author_taxonomy_authors($
   $author_count = count($author_names);
 
   switch ($author_count) {
-    case 0 : // No authors (theme_author_taxonomy_output() should have caught this)
+    case 0 : // No authors. Return nothing.
       break;
 
     case 1 : // One author (output: "Name1")
@@ -751,6 +1057,7 @@ function theme_author_taxonomy_authors($
  * Returns the timestamp in the format chosen on the admin settings page (themeable).
  */
 function theme_author_taxonomy_timestamp($timestamp) {
+
   $type = variable_get('author_taxonomy_timestamp_type', array('medium'));
   $format = variable_get('author_taxonomy_timestamp_format', 'j F Y');
 
@@ -763,8 +1070,9 @@ function theme_author_taxonomy_timestamp
  * 
  * This function is called only if "Remove author names from each node's list of
  * terms" is checked. In this case, author names have already been removed from
- * the $taxonomy array
+ * the $taxonomy array.
  */
 function theme_author_taxonomy_terms($taxonomy) {
   return theme('links', $taxonomy, array('class' => 'links inline'));
 }
+
diff -Nurp author_taxonomy/author_taxonomy.views.inc author_taxonomy/author_taxonomy.views.inc
--- author_taxonomy/author_taxonomy.views.inc	1969-12-31 16:00:00.000000000 -0800
+++ author_taxonomy/author_taxonomy.views.inc	2012-02-01 14:20:38.000000000 -0800
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * Implementation of hook_views_handler
+ *
+ * Views calls this function to find out what handlers we have and what files they
+ * are in; the parent is the parent handler class, so that views can load the files
+ * in the right order.
+ *
+ */
+function author_taxonomy_views_handlers() {
+  return array(
+    'info' => array(
+      'path' => drupal_get_path('module', 'author_taxonomy'),
+                   ),
+    'handlers' => array(
+      'author_taxonomy_handler_field_term_node_tid' => array(
+        'parent' => 'views_handler_field_term_node_tid',
+        'file' => 'author_taxonomy_handler_field_term_node_tid.inc',
+	),
+      ),
+    );
+}
+
+/**
+ * Implementation of hook_views_data_alter().
+ *
+ * This modified a $data structure that is how Views decides to call our handler
+ * for the display of a particular field from a particular table.  Our handler will
+ * not be called unless a field is mapped to it here.
+ *
+ */
+function author_taxonomy_views_data_alter(&$data) {
+
+  // tid field
+  $data['term_node']['tid'] = array(
+    'title' => t('Author'),
+    'help' => t('Author Taxonomy'),
+    'field' => array(
+      'title' => t('Author terms'),
+      'help' => t('Display the authors associated with the node via the author_taxonomy vocabulary.'),
+      'handler' => 'author_taxonomy_handler_field_term_node_tid',
+      //'skip base' => 'term_data',
+    ),
+  );
+}
+
diff -Nurp author_taxonomy/author_taxonomy_handler_field_term_node_tid.inc author_taxonomy/author_taxonomy_handler_field_term_node_tid.inc
--- author_taxonomy/author_taxonomy_handler_field_term_node_tid.inc	1969-12-31 16:00:00.000000000 -0800
+++ author_taxonomy/author_taxonomy_handler_field_term_node_tid.inc	2012-03-28 08:02:19.000000000 -0700
@@ -0,0 +1,88 @@
+<?php
+
+/**
+ * Field handler for terms.
+ */
+class author_taxonomy_handler_field_term_node_tid extends views_handler_field_term_node_tid {
+  //  class author_taxonomy_handler_field_term_node_tid extends views_handler_XXXXXXXXX {
+
+  function construct() {
+    parent::construct();
+  }
+
+
+  function init(&$view, $options) {
+    parent::init($view, $options);
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+    return $options;
+  }
+
+  /**
+   * Provide "link to term" option.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+  }
+
+  /**
+   * Add this term to the query
+   */
+  function query() {
+    parent::add_additional_fields();
+  }
+
+  function pre_render($values) {
+    //dsm("RGR DEBUG: in author_taxonomy handler pre_render: values= ".print_r($values, TRUE));
+
+    $vid = variable_get('author_taxonomy_vocab', 0);
+    $taxonomy = taxonomy_vocabulary_load($vid);
+    // For user defined order
+    if ( variable_get('author_taxonomy_user_defined_order', FALSE ) && is_array($values) && count($values) ) {
+      // This section is a copy of the parent::pre_render, except that when the $this->items[] array is
+      // built, it is put in the right order
+
+      $this->field_alias = $this->aliases['vid'];
+      $vids = array();
+      foreach ($values as $result) {
+				if (!empty($result->{$this->aliases['vid']})) {
+					$vids[] = $result->{$this->aliases['vid']};
+				}
+      }
+
+      if ($vids) {
+				$voc = '';
+				if (!empty($this->options['limit']) && !empty($this->options['vids'])) {
+					$voc = " AND td.vid IN (" . implode(', ', array_keys(array_filter($this->options['vids']))) . ")";
+				}
+
+        // This query is the only thing different about this pre_render from the parent's.  An INNER JOIN
+        // the author_taxonomy_term_order was added to get the weight from there instead of term_data.
+        $result = db_query("SELECT tn.vid AS node_vid, td.tid, td.vid, td.name, td.description, atto.weight, 
+															v.name as vocabulary FROM term_data td 
+															INNER JOIN term_node tn  ON td.tid = tn.tid  
+															INNER JOIN vocabulary v ON v.vid = td.vid  
+															INNER JOIN author_taxonomy_term_order atto ON atto.vid = tn.vid AND atto.tid = td.tid 
+															WHERE tn.vid IN (" . implode(', ', $vids) . ")$voc ORDER BY atto.weight, td.name");
+
+				while ($term = db_fetch_object($result)) {
+					$this->items[$term->node_vid][$term->tid]['name'] = check_plain($term->name);
+					$this->items[$term->node_vid][$term->tid]['tid'] = $term->tid;
+					$this->items[$term->node_vid][$term->tid]['vid'] = $term->vid;
+					$this->items[$term->node_vid][$term->tid]['vocabulary'] = check_plain($term->vocabulary);
+			
+					if (!empty($this->options['link_to_taxonomy'])) {
+						$this->items[$term->node_vid][$term->tid]['make_link'] = TRUE;
+						$this->items[$term->node_vid][$term->tid]['path'] = taxonomy_term_path($term);
+					}
+				}
+      }
+      
+    } else {
+      parent::pre_render($values);
+    }
+  }
+}
+
