Index: README.txt
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/community_tags/README.txt,v
retrieving revision 1.3.4.1
diff -u -r1.3.4.1 README.txt
--- README.txt	11 Apr 2007 12:36:57 -0000	1.3.4.1
+++ README.txt	3 May 2007 00:40:40 -0000
@@ -23,7 +23,7 @@
 
      Administer > Site Building > Modules
 
-4. Create a free tagging vocabulary by going to:
+4. Create a vocabulary by going to:
 
      Administer > Content > Categories
 
Index: community_tags.css
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/community_tags/community_tags.css,v
retrieving revision 1.3
diff -u -r1.3 community_tags.css
--- community_tags.css	11 Apr 2007 12:31:32 -0000	1.3
+++ community_tags.css	5 May 2007 04:36:43 -0000
@@ -1,14 +1,14 @@
 div.tag-widget {
 }
 
-div.tag-widget ul.inline-tags {
+div.tag-widget ul.inline-tags, div.tag-basket ul.inline-tags {
   list-style-type: none;
   list-style-image: none;
   background: url('tag.png') no-repeat 0 3px;
   margin: 0;
   padding: 0 0 0 22px;
 }
-div.tag-widget ul.inline-tags li {
+div.tag-widget ul.inline-tags li, div.tag-basket ul.inline-tags li {
   list-style-type: none;
   list-style-image: none;
   background: none;
@@ -23,12 +23,16 @@
   background: #fdd url('delete.png') no-repeat 100% 50%;
   z-index: 2;
 }
+div.tag-basket ul.inline-tags li:hover, div.tag-basket ul.inline-tags li.hover {
+  background: #98fb98 url('add.png') no-repeat 100% 50%;
+  z-index: 2;
+}
 div.tag-widget input.form-tags {
   width: 16em;
 }
 .block div.tag-widget input.form-tags {
   width: 12em;
 }
-html.js span.no-js, html.js input.form-tags {
+html.js span.no-js, html.js input.form-tags, html.js select.form-taxonomy {
   display: none;
 }
Index: community_tags.js
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/community_tags/community_tags.js,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 community_tags.js
--- community_tags.js	11 Apr 2007 22:44:49 -0000	1.1.2.1
+++ community_tags.js	8 May 2007 19:35:31 -0000
@@ -13,7 +13,7 @@
   for (i in data) {
     var name = prefix.length ? (prefix +'[' + i +']') : i;
     if (out.length) out += '&';
-    if (typeof data[i] == 'object') {
+    if ((typeof data[i] == 'object') || (typeof data[i] == 'array')) {
       out += Drupal.serialize(data[i], name);
     }
     else {
@@ -26,11 +26,14 @@
 
 if (Drupal.jsEnabled) {
   $(document).ready(function () {
+    // Process free tagging vocabularies.
     // Note: all tag fields are autocompleted, and have already been initialized at this point.
     $('input.form-tags').each(function () {
       // Hide submit buttons.
       $('input[@type=submit]', this.form).hide();
 
+      var nid = $('input[@name=nid]', this.form).attr('value');
+
       // Fetch settings.
       var o = Drupal.settings.communityTags;
       var sequence = 0;
@@ -39,40 +42,40 @@
       var textfield = $(this).val('').css('display', 'inline');
 
       // Prepare the add Ajax handler and add the button.
-      var addHandler = function () {
+      var addHandler = function (nid) {
         // Send existing tags and new tag string.
-        $.post(o.url, Drupal.serialize({ sequence: ++sequence, tags: o.tags, add: textfield[0].value }), function (data) {
+        $.post(o.url +'/'+ nid, Drupal.serialize({ sequence: ++sequence, tags: o.tags[nid], add: textfield[0].value }), function (data) {
           data = Drupal.parseJson(data);
           if (data.status && sequence == data.sequence) {
-            o.tags = data.tags;
-            updateList();
+            o.tags[data.nid] = data.taxonomy;
+            updateList(data.nid);
           }
         });
         
         // Add tag to local list
-        o.tags.push(textfield[0].value);
-        o.tags.sort();
-        updateList();
+        o.tags[nid].push(textfield[0].value);
+        o.tags[nid].sort();
+        updateList(nid);
         
         // Clear field and focus it.
         textfield.val('').focus();
       };
-      var button = $('<input type="button" value="'+ Drupal.checkPlain(o.add) +'" />').click(addHandler);
-      $(this.form).submit(function () { addHandler(); return false; });
+      var button = $('<input type="button" value="'+ Drupal.checkPlain(o.addButton) +'" />').click(function () { addHandler(nid)});
+      $(this.form).submit(function () { addHandler(nid); return false; });
 
       // Prepare the delete Ajax handler.
-      var deleteHandler = function () {
+      var deleteHandler = function (nid) {
         // Remove tag from local list.
         var i = $(this).attr('key');
-        o.tags.splice(i, 1);
-        updateList();
+        o.tags[nid].splice(i, 1);
+        updateList(nid);
 
         // Send new tag list.
-        $.post(o.url, Drupal.serialize({ sequence: ++sequence, tags: o.tags, add: '' }), function (data) {
+        $.post(o.url +'/'+ nid, Drupal.serialize({ sequence: ++sequence, tags: o.tags[nid], add: '' }), function (data) {
           data = Drupal.parseJson(data);
           if (data.status && sequence == data.sequence) {
-            o.tags = data.tags;
-            updateList();
+            o.tags[data.nid] = data.taxonomy;
+            updateList(data.nid);
           }
         });
 
@@ -81,12 +84,14 @@
       };
 
       // Callback to update the tag list.
-      function updateList() {
+      function updateList(nid) {
         list.empty();
-        for (i in o.tags) {
-          list.append('<li key="'+ Drupal.checkPlain(i) +'">'+ Drupal.checkPlain(o.tags[i]) +'</li>');
+        for (i in o.tags[nid]) {
+          list.append('<li key="'+ Drupal.checkPlain(i) +'">'+ Drupal.checkPlain(o.tags[nid][i]) +'</li>');
         }
-        $('li', list).click(deleteHandler);
+        $('li', list).click(function () {
+          deleteHandler(nid);
+        });
       }
 
       // Create widget markup.
@@ -95,7 +100,139 @@
       widget.append(textfield).append(button);
       var list = $('ul', widget);
 
-      updateList();
+      updateList(nid);
+    });
+
+    // Process regular vocabularies.
+    $('select.form-taxonomy').each(function () {
+      // Hide submit buttons.
+      $('input[@type=submit]', this.form).hide();
+
+      // Fetch settings.
+      var o = Drupal.settings.communityTags;
+      if (typeof o.tags != 'object') {
+        o.tags = {};
+      }
+      var nid = $('input[@name=nid]', this.form).attr('value');
+      o.tags[nid] = [];
+      var sequence = 0;
+
+      // Hide the select.
+      var select = $(this).css('display', 'none');
+
+      var multiple = $(this).attr('multiple') == 'multiple';
+
+      // Read in data from the select.
+      $('option', select).each(function () {
+        if (($(this).attr('value') != 'undefined') && ($(this).attr('value') != 0)) {
+          o.tags[nid].push({name: $(this).html(), tid: $(this).attr('value'), status: $(this).attr('selected') == 'selected'});
+        }
+      });
+
+      // Prepare the add Ajax handler and add the button.
+      var addHandler = function (nid, elt) {
+        var taxonomy = [];
+
+        // Set tag status in local list.
+        for (var i in o.tags[nid]) {
+          if ($(elt).attr('id') == o.tags[nid][i].tid) {
+            o.tags[nid][i].status = true;
+          }
+          // If it's not a multiple select vocabulary, only allow
+          // one term.
+          else if (!multiple) {
+            o.tags[nid][i].status = false;
+          }
+          if (o.tags[nid][i].status == true) {
+            taxonomy.push(o.tags[nid][i].tid);
+          }
+        }
+
+        // Send term data.
+        $.post(o.url +'/'+ nid, Drupal.serialize({ sequence: ++sequence, taxonomy: taxonomy }), function (data) {
+          data = Drupal.parseJson(data);
+          if (data.status && sequence == data.sequence) {
+            // Set tag status in local list.
+            for (var i in o.tags[data.nid]) {
+              o.tags[data.nid][i].status = false;
+              for (var j in data.taxonomy) {
+                if (o.tags[data.nid][i].tid == data.taxonomy[j]) {
+                  o.tags[data.nid][i].status = true;
+                  break;
+                }
+              }
+            }
+            updateLists(data.nid);
+          }
+        });
+
+        updateLists(nid);
+
+      };
+      $(this.form).submit(function () { return false; });
+
+      // Prepare the delete Ajax handler.
+      var deleteHandler = function (nid) {
+
+        var taxonomy = [];
+
+        // Set tag status in local list.
+        for (var i in o.tags[nid]) {
+          if ($(this).attr('id') == o.tags[nid][i].tid) {
+            o.tags[nid][i].status = false;
+          }
+          if (o.tags[nid][i].status == true) {
+            taxonomy.push(o.tags[nid][i].tid);
+          }
+        }
+        updateLists(nid);
+
+        // Send new tag list.
+        $.post(o.url +'/'+ nid, Drupal.serialize({ sequence: ++sequence, taxonomy: taxonomy }), function (data) {
+          data = Drupal.parseJson(data);
+          if (data.status && sequence == data.sequence) {
+            // Set tag status in local list.
+            for (var i in o.tags[data.nid]) {
+              o.tags[data.nid][i].status = false;
+              for (var j in data.taxonomy) {
+                if ( o.tags[data.nid][i].tid == data.taxonomy[j]) {
+                  o.tags[data.nid][i].status = true;
+                  break;
+                }
+              }
+            }
+            updateLists(data.nid);
+          }
+        });
+
+      };
+
+      // Callback to update the tag lists.
+      function updateLists(nid) {
+        list.empty();
+        basket.empty();
+        for (i in o.tags[nid]) {
+          var target = o.tags[nid][i].status ? list : basket;
+          var text = o.tags[nid][i].status ? Drupal.checkPlain(o.remove) : Drupal.checkPlain(o.add);
+          target.append('<li id="'+ o.tags[nid][i].tid +'">'+ text +' '+ o.tags[nid][i].name +'</li>');
+        }
+        $('li', list).click(function () {
+          deleteHandler(nid, this);
+        });
+        $('li', basket).click(function () {
+          addHandler(nid, this);
+        });
+      }
+
+      // Create widget markup.
+      var listWidget = $('<div class="tag-widget"><ul class="inline-tags clear-block"></ul></div>');
+      select.before(listWidget).hide();
+      var basketWidget = $('<div class="tag-basket"><ul class="inline-tags clear-block"></ul></div>');
+      listWidget.after(basketWidget);
+      var list = $('ul', listWidget);
+      var basket = $('ul', basketWidget);
+
+      updateLists(nid);
     });
   });
 }
\ No newline at end of file
Index: community_tags.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/community_tags/community_tags.module,v
retrieving revision 1.32.2.1
diff -u -r1.32.2.1 community_tags.module
--- community_tags.module	3 May 2007 09:14:45 -0000	1.32.2.1
+++ community_tags.module	8 May 2007 20:35:22 -0000
@@ -14,7 +14,7 @@
 function community_tags_help($section) {
   switch ($section) {
     case 'admin/settings/community-tags':
-      return t('To set up community tagging, you must first <a href="@taxonomy">create a normal free tagged vocabulary</a>. Then activate community tagging on such a vocabulary below, and set the <a href="@workflow">workflow options</a> for node types to control how users can tag nodes.', array('@taxonomy' => url('admin/content/taxonomy'), '@workflow' => url('admin/content/types')));
+      return t('To set up community tagging, you must first <a href="@taxonomy">create a normal vocabulary</a>. Then activate community tagging on such a vocabulary below, and set the <a href="@workflow">workflow options</a> for node types to control how users can tag nodes.', array('@taxonomy' => url('admin/content/taxonomy'), '@workflow' => url('admin/content/types')));
       break;
   }
 }
@@ -159,6 +159,8 @@
  */
 function community_tags_node_view($node, $inline = TRUE) {
   global $user;
+  static $sent;
+
   if (is_numeric($node)) {
     $node = node_load($node);
   }
@@ -167,30 +169,34 @@
     drupal_set_title(check_plain($node->title));
   }
 
-  $cloud = theme('community_tags', 'node', NULL, $node->nid);
-
   $vid = array_shift(community_tags_for_node($node));
+  $vocabulary = taxonomy_get_vocabulary($vid);
+
+  $cloud = $vocabulary->tags ? theme('community_tags', 'node', NULL, $node->nid) : NULL;
+
   $tags = community_tags_get_user_node_tags($user->uid, $node->nid);
   $names = array();
 
   if (!count($tags)) {
     // User has not yet added tags to this node yet. Show form.
-    $output .= drupal_get_form('community_tags_form', array('cloud' => $cloud, 'nid' => $node->nid, 'vid' => $vid, 'tags' => NULL, 'inline' => $inline));
+    $output .= drupal_get_form('community_tags_form', array('cloud' => $cloud, 'nid' => $node->nid, 'vid' => $vid, 'taxonomy' => NULL, 'inline' => $inline));
   }
   elseif (user_access('edit own tags')) {
     // User has already tagged this node, but can edit their tags. Show form
     // with the user's tags pre-populated.
     $names = community_tags_flatten($tags);
-    $tags = taxonomy_implode_tags($tags);
-    $output .= drupal_get_form('community_tags_form', array('cloud' => $cloud, 'nid' => $node->nid, 'vid' => $vid, 'tags' => $tags, 'inline' => $inline));
+    $taxonomy = $vocabulary->tags ? array('tags' => taxonomy_implode_tags($tags)) : array_keys($tags);
+    $output .= drupal_get_form('community_tags_form', array('cloud' => $cloud, 'nid' => $node->nid, 'vid' => $vid, 'taxonomy' => $taxonomy, 'inline' => $inline));
   }
   else {
     // Sorry, no more adding tags for you!
     $output .= '<p>'. t('You have already tagged this post. Your tags: ') . theme('community_tags', 'user_node', NULL, $user->uid, $node->nid) .'</p>';
   }
 
-  drupal_add_js(array('communityTags' => array('tags' => $names, 'url' => url('community-tags/'. $node->nid), 'add' => t('Add'))), 'setting');
-
+  // Set data for this node.
+  if ($vocabulary->tags) {
+    community_tags_node_data($node->nid, $names);
+  }
   return $output;
 }
 
@@ -201,6 +207,34 @@
   return array('tag content', 'edit own tags');
 }
 
+
+/**
+ * Store and return node data for output in Javascript settings.
+ */
+function community_tags_node_data($nid = NULL, $names = NULL) {
+  static $nodes = array();
+  if ($nid) {
+    $nodes[$nid] = $names;
+  }
+  else {
+    return $nodes;
+  }
+}
+
+/**
+ * Implementation of hook_footer().
+ */
+function community_tags_footer() {
+  static $sent;
+
+  // Only set Javascript once.
+  if ($sent == NULL) {
+    $settings = array('communityTags' => array('tags' => community_tags_node_data(), 'url' => url('community-tags'), 'addButton' => t('Add'), 'add' => t('add to'), 'remove' => t('remove from')));
+    drupal_add_js($settings, 'setting');
+    $sent = TRUE;
+  }
+}
+
 /**
  * Implementation of hook_nodeapi().
  */
@@ -229,7 +263,7 @@
       global $user;
       // Show quick tag form for this node if we're on a node page view and the
       // form is enabled for this node and the default quick tag vocab is set.
-      if (!$teaser && $node->community_tags_form) {
+      if ($node->community_tags_form && (!$teaser || variable_get('community_tags_teaser_'. $node->type, 0))) {
         $node->content['community_tags'] = array(
           '#value' => community_tags_node_view($node, TRUE),
           '#weight' => 50,
@@ -248,7 +282,7 @@
   community_tags_rehash();
 
   // Build list of available free-tagging vocabularies
-  $vocabs = db_query('SELECT v.vid, v.name FROM {vocabulary} v WHERE v.tags = 1 ORDER BY v.weight, v.name');
+  $vocabs = db_query('SELECT v.vid, v.name FROM {vocabulary} v ORDER BY v.weight, v.name');
   while ($vocabulary = db_fetch_object($vocabs)) {
     $options[$vocabulary->vid] = $vocabulary->name;
   }
@@ -286,6 +320,12 @@
       '#options' => $modes,
       '#description' => t('How should users be allowed to tag content?')
     );
+    $form['workflow']['community_tags_teaser'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Show on node teasers'),
+      '#default_value' => variable_get('community_tags_teaser_'. $form['#node_type']->type, 0),
+      '#description' => t('When the tagging form is displayed inline, do you wish to show it on node teasers? If this option is not checked, the form only displays only on full node views.'),
+    );
   }
 }
 
@@ -306,35 +346,48 @@
  * Quick tag form
  */
 function community_tags_form($edit, $title = NULL) {
-  $form['cloud'] = array(
-    '#type' => 'markup',
-    '#title' => t('All tags'),
-    '#value' => $edit['cloud'],
-  );
-  
-  $access = user_access('tag content');
 
-  $form['tags'] = array(
-    '#type' => 'textfield',
-    '#title' => t('My tags'),
-    '#maxlength' => 100,
-    '#default_value' => $edit['tags'],
-    '#required' => FALSE,
-    '#autocomplete_path' => 'taxonomy/autocomplete/'. $edit['vid'],
-    '#description' => t('<span class="no-js">A comma-separated list of terms describing this content. </span>Example: funny, bungee jumping, "Company, Inc.".'),
-    '#attributes' => array('class' => 'form-tags'),
-    '#access' => $access,
-  );
-  if ($edit['inline']) {
-    $form['tags']['#size'] = 20;
-  }
-  
-  if (!$access) {
-    $destination = drupal_get_destination();
-    $form['login'] = array(
+  // Only show if there are terms already and this is a freetagging vocabulary.
+  if ($edit['cloud']) {
+    $form['cloud'] = array(
       '#type' => 'markup',
-      '#value' => '<div>'. t('<a href="@login">Login</a> or <a href="@register">register</a> to tag items', array('@login' => url('user/login', $destination), '@register' => url('user/register', $destination))) .'</div>',
+      '#title' => t('All tags'),
+      '#value' => $edit['cloud'],
+    );
+  }
+
+  $vocabulary = taxonomy_get_vocabulary($edit['vid']);
+  $access = user_access('tag content');
+
+  if ($vocabulary->tags) {
+    $form['taxonomy'] = array(
+      '#tree' => TRUE,
     );
+    $form['taxonomy']['tags'] = array(
+      '#type' => 'textfield',
+      '#title' => t('My tags'),
+      '#maxlength' => 100,
+      '#default_value' => $edit['tags'],
+      '#required' => FALSE,
+      '#autocomplete_path' => 'taxonomy/autocomplete/'. $edit['vid'],
+      '#description' => t('<span class="no-js">A comma-separated list of terms describing this content. </span>Example: funny, bungee jumping, "Company, Inc.".'),
+      '#attributes' => array('class' => 'form-tags'),
+      '#access' => $access,
+    );
+    if ($edit['inline']) {
+      $form['taxonomy']['tags']['#size'] = 20;
+    }
+    if (!$access) {
+      $destination = drupal_get_destination();
+      $form['login'] = array(
+        '#type' => 'markup',
+        '#value' => '<div>'. t('<a href="@login">Login</a> or <a href="@register">register</a> to tag items', array('@login' => url('user/login', $destination), '@register' => url('user/register', $destination))) .'</div>',
+      );
+    }
+  }
+  else {
+    $form['taxonomy'] = taxonomy_form($edit['vid'], $edit['taxonomy']);
+    $form['taxonomy']['#attributes'] = array('class' => 'form-taxonomy');
   }
 
   $form['submit'] = array(
@@ -343,7 +396,7 @@
   );
 
   $form['nid'] = array(
-    '#type' => 'value',
+    '#type' => 'hidden',
     '#value' => $edit['nid'],
   );
 
@@ -359,17 +412,25 @@
  * Validate the quick tag form.
  */
 function community_tags_form_validate($form_id, $form_values) {
-  if ($form_values['tags'] == '') {
+  if (isset($form_values['taxonomy']['tags']) && $form_values['taxonomy']['tags'] == '') {
     form_set_error('tags', t('You must enter at least one tag.'));
   }
+  if (isset($form_values['taxonomy']) && empty($form_values['taxonomy'])) {
+    form_set_error('tags', t('You must select at least one tag.'));
+  }
 }
 
 /**
- * Submit callback for quick tag form.
+ * Submit callback for tag form.
  */
 function community_tags_form_submit($form_id, $form_values) {
+  // If a single select value has been submitted we need to translate it
+  // into an array.
+  if (is_numeric($form_values['taxonomy'])) {
+    $form_values['taxonomy'] = array($form_values['taxonomy']);
+  }
   global $user;
-  community_tags_taxonomy_node_save($form_values['nid'], array('tags' => array($form_values['vid'] => $form_values['tags'])), FALSE, $user->uid);
+  community_tags_taxonomy_node_save($form_values['nid'], $form_values['taxonomy'], FALSE, $user->uid);
 
   return array('node/'. $form_values['nid']);
 }
@@ -379,7 +440,7 @@
  * @ingroup themeable
  */
 function theme_community_tags_form($form) {
-  $output .= theme('form_element', array('#title' => t('All tags')), drupal_render($form['cloud']));
+  $output = isset($form['cloud']) ? theme('form_element', array('#title' => t('All tags')), drupal_render($form['cloud'])) : '';
 
   $output .= drupal_render($form);
 
@@ -410,29 +471,47 @@
     return;
   }
 
-  $tags = is_array($_POST['tags']) ? $_POST['tags'] : array();
-
-  // Merge in new tag and save
-  $tags = array_unique(array_merge($tags, taxonomy_explode_tags($_POST['add'])));
-  $vid = array_shift(community_tags_for_node($node));
-  community_tags_taxonomy_node_save($node->nid, array('tags' => array($vid => $tags)), FALSE, $user->uid);
-
-  // Fetch updated list
-  $tags = community_tags_flatten(community_tags_get_user_node_tags($user->uid, $node->nid));
+  // Process free tagging vocabulary.
+  if (isset($_POST['tags'])) {
+    $tags = is_array($_POST['tags']) ? $_POST['tags'] : array();
+
+    // Merge in new tag and save
+    $tags = array_unique(array_merge($tags, taxonomy_explode_tags($_POST['add'])));
+    $vid = array_shift(community_tags_for_node($node));
+    community_tags_taxonomy_node_save($node->nid, array('tags' => array($vid => $tags)), FALSE, $user->uid);
+    // Fetch updated list
+    $tags = community_tags_flatten(community_tags_get_user_node_tags($user->uid, $node->nid));
+  }
+  // Process regular vocabulary.
+  else {
+    community_tags_taxonomy_node_save($node->nid, $_POST['taxonomy'], FALSE, $user->uid);
+    // Fetch updated list.
+    $tags = array_keys(community_tags_get_user_node_tags($user->uid, $node->nid));
+  }
 
   // Output JSON
-  print drupal_to_js(array('status' => TRUE, 'tags' => $tags, 'sequence' => $_POST['sequence']));
+  print drupal_to_js(array('status' => TRUE, 'nid' => $nid, 'taxonomy' => $tags, 'sequence' => $_POST['sequence']));
   drupal_set_header('Content-Type: text/javascript; charset=utf-8');
 }
 
 /**
  * Save community_tags term associations and counts for a given node.
  */
-function community_tags_taxonomy_node_save($nid, $terms, $is_owner, $uid) {
+function community_tags_taxonomy_node_save($nid, $taxonomy, $is_owner, $uid) {
   $community_tagged = variable_get('community_tags_vocabularies', array());
   if (count($community_tagged) == 0) {
     return;
   }
+  // Process an array of tids for a regular taxonomy, if present.
+  // Here we don't need to add new terms or delete existing ones.
+  if (is_array($taxonomy) && !isset($taxonomy['tags'])) {
+    // Delete terms by this user.
+    db_query('DELETE FROM {community_tags} WHERE nid = %d AND uid = %d', $nid, $uid);
+    foreach ($taxonomy as $tid) {
+      db_query('INSERT INTO {community_tags} (tid, nid, uid, date) VALUES (%d, %d, %d, %d)', $tid, $nid, $uid, time());
+    }
+    return;
+  }
 
   // If we're adding tags from the node add/edit page, then we want to delete
   // any tags that aren't entered to allow admins to remove node tags.
@@ -450,9 +529,9 @@
   $tids = array();
   // Free tagging vocabularies do not send their tids in the form,
   // so we'll detect them here and process them independently.
-  if (isset($terms['tags'])) {
-    $typed_input = $terms['tags'];
-    unset($terms['tags']);
+  if (isset($taxonomy['tags'])) {
+    $typed_input = $taxonomy['tags'];
+    unset($taxonomy['tags']);
 
     foreach ($typed_input as $vid => $vid_value) {
       $typed_terms = is_array($vid_value) ? $vid_value : taxonomy_explode_tags($vid_value);
@@ -547,7 +626,6 @@
       db_query('DELETE FROM {term_node} WHERE nid = %d AND tid = %d', $tag->nid, $tag->tid);
     }
   }
-
 }
 
 /**
