Index: category.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/category/category.inc,v
retrieving revision 1.63
diff -u -p -r1.63 category.inc
--- category.inc	22 Nov 2006 08:22:23 -0000	1.63
+++ category.inc	5 Jan 2007 15:20:47 -0000
@@ -100,7 +100,7 @@ function category_get_container($cnid) {
  */
 function category_get_containers($type = NULL) {
   $type_sql = $type ? " WHERE nt.type = '%s'" : "";
-  $result = db_query("SELECT c.*, n.title, n.status, n.moderate, nt.type, cd.allowed_parent FROM {category_cont} c INNER JOIN {category} t ON c.cid = t.cid INNER JOIN {node} n ON c.cid = n.nid LEFT JOIN {category_cont_node_types} nt ON c.cid = nt.cid LEFT JOIN {category_cont_distant} cd ON c.cid = cd.cid". $type_sql ." ORDER BY t.weight, n.title", $type);
+  $result = db_query("SELECT c.*, n.title, n.status, nt.type, cd.allowed_parent FROM {category_cont} c INNER JOIN {category} t ON c.cid = t.cid INNER JOIN {node} n ON c.cid = n.nid LEFT JOIN {category_cont_node_types} nt ON c.cid = nt.cid LEFT JOIN {category_cont_distant} cd ON c.cid = cd.cid". $type_sql ." ORDER BY t.weight, n.title", $type);
 
   $containers = array();
   $node_types = array();
@@ -153,8 +153,8 @@ function category_is_cat_or_cont($nid, $
 }
 
 /**
- * Given a new or existing node, and a type of either 'category-cat' or
- * 'category-cont' (or undefined), determine if a category node is a category
+ * Given a new or existing node, and a type of either 'category_cat' or
+ * 'category_cont' (or undefined), determine if a category node is a category
  * or a container, and return its type. This function assumes that the
  * node is either a category or a container - it will not return the correct
  * value if the node is neither (this is by design).
@@ -165,23 +165,23 @@ function category_is_cat_or_cont($nid, $
  * @param $node
  *   The node being tested. Does not have to be fully populated.
  * @param $type
- *   The type of category being used. Either 'category-cat', 'category-cont',
+ *   The type of category being used. Either 'category_cat', 'category_cont',
  *   or an empty value (such as NULL).
  *
  * @return
- *   Either 'category-cat' or 'category-cont' (never ANYTHING else).
+ *   Either 'category_cat' or 'category_cont' (never ANYTHING else).
  */
 function category_node_get_type($node, $type = NULL) {
   if (empty($type)) {
     $type = $node->type;
   }
-  if (empty($type) || !($type == 'category-cat' || $type == 'category-cont')) {
+  if (empty($type) || !($type == 'category_cat' || $type == 'category_cont')) {
     $category = category_get_category($node->nid);
     if ($category->cnid) {
-      $type = 'category-cat';
+      $type = 'category_cat';
     }
     else {
-      $type = 'category-cont';
+      $type = 'category_cont';
     }
   }
 
@@ -201,7 +201,7 @@ function category_get_parents($cid, $key
 
   if (($distant && !isset($distant_parents)) || (!$distant && !isset($parents)) || $reset) {
     $distant_sql = $distant ? '' : ' AND (c.cnid = cc.cnid OR c.cnid = 0)';
-    $result = db_query(db_rewrite_sql('SELECT c.*, h.cid AS child, n.title, cn.admin_title FROM {category} c INNER JOIN {category_hierarchy} h ON c.cid = h.parent INNER JOIN {node} n ON c.cid = n.nid LEFT JOIN {category_cont} cn ON c.cid = cn.cid INNER JOIN {category} cc ON h.cid = cc.cid WHERE n.status = 1 AND n.moderate = 0'. $distant_sql .' ORDER BY c.weight, n.title'), $cid);
+    $result = db_query(db_rewrite_sql('SELECT c.*, h.cid AS child, n.title, cn.admin_title FROM {category} c INNER JOIN {category_hierarchy} h ON c.cid = h.parent INNER JOIN {node} n ON c.cid = n.nid LEFT JOIN {category_cont} cn ON c.cid = cn.cid INNER JOIN {category} cc ON h.cid = cc.cid WHERE n.status = 1'. $distant_sql .' ORDER BY c.weight, n.title'), $cid);
     if ($distant) {
       $distant_parents = array();
     }
@@ -247,7 +247,7 @@ function category_get_children($cid, $cn
   static $children;
 
   if ($cnid) {
-    $result = db_query(db_rewrite_sql('SELECT c.*, n.title FROM {category} c INNER JOIN {category_hierarchy} h ON c.cid = h.cid INNER JOIN {node} n ON c.cid = n.nid WHERE h.parent = %d AND n.status = 1 AND n.moderate = 0 AND c.cnid = %d ORDER BY c.weight, n.title'), $cid, $cnid);
+    $result = db_query(db_rewrite_sql('SELECT c.*, n.title FROM {category} c INNER JOIN {category_hierarchy} h ON c.cid = h.cid INNER JOIN {node} n ON c.cid = n.nid WHERE h.parent = %d AND n.status = 1 AND c.cnid = %d ORDER BY c.weight, n.title'), $cid, $cnid);
 
     $results = array();
     while ($category = db_fetch_object($result)) {
@@ -257,7 +257,7 @@ function category_get_children($cid, $cn
     return $results;
   }
   elseif (!isset($children) || $reset) {
-    $result = db_query(db_rewrite_sql('SELECT c.*, h.parent, n.title FROM {category} c INNER JOIN {category_hierarchy} h ON c.cid = h.cid INNER JOIN {node} n ON c.cid = n.nid WHERE n.status = 1 AND n.moderate = 0 ORDER BY c.weight, n.title'), $cid);
+    $result = db_query(db_rewrite_sql('SELECT c.*, h.parent, n.title FROM {category} c INNER JOIN {category_hierarchy} h ON c.cid = h.cid INNER JOIN {node} n ON c.cid = n.nid WHERE n.status = 1 ORDER BY c.weight, n.title'), $cid);
 
     $children = array();
     while ($category = db_fetch_object($result)) {
@@ -395,7 +395,7 @@ function category_get_tree($cnid, $paren
     $distant_sql = ($distant) ? '' : 'AND c.cnid = %d ';
 
     $children[$cnid] = array();
-    $result = db_query(db_rewrite_sql('SELECT c.cid, c.*, h.parent, n.title, cn.admin_title FROM {category} c INNER JOIN {category_hierarchy} h ON c.cid = h.cid INNER JOIN {node} n ON c.cid = n.nid LEFT JOIN {category_cont} cn ON c.cid = cn.cid LEFT JOIN {category} c2 ON h.parent = c2.cid WHERE (c2.cid IS NOT NULL OR h.parent = 0) AND n.status = 1 AND n.moderate = 0 '. $distant_sql .'ORDER BY c.weight, n.title', 'n', 'nid'), $cnid);
+    $result = db_query(db_rewrite_sql('SELECT c.cid, c.*, h.parent, n.title, cn.admin_title FROM {category} c INNER JOIN {category_hierarchy} h ON c.cid = h.cid INNER JOIN {node} n ON c.cid = n.nid LEFT JOIN {category_cont} cn ON c.cid = cn.cid LEFT JOIN {category} c2 ON h.parent = c2.cid WHERE (c2.cid IS NOT NULL OR h.parent = 0) AND n.status = 1 '. $distant_sql .'ORDER BY c.weight, n.title', 'n', 'nid'), $cnid);
 
     while ($category = db_fetch_object($result)) {
       if (!$distant && $depth == 0) {
@@ -415,15 +415,16 @@ function category_get_tree($cnid, $paren
   if ($children[$cnid][$parent]) {
     foreach ($children[$cnid][$parent] as $child) {
       if ($max_depth > $depth) {
-        $categories[$cnid][$child]->depth = $depth;
+        $cat = drupal_clone($categories[$cnid][$child]);
+        $cat->depth = $depth;
         // The "parent" attribute is not useful, as it would show one parent only.
-        unset($categories[$cnid][$child]->parent);
-        $categories[$cnid][$child]->parents = $parents[$cnid][$child];
+        unset($cat->parent);
+        $cat->parents = $parents[$cnid][$child];
 
-        if (!$categories[$cnid][$child]->cnid && empty($categories[$cnid][$child]->admin_title)) {
-          $categories[$cnid][$child]->admin_title = $categories[$cnid][$child]->title;
+        if (!$cat->cnid && empty($cat->admin_title)) {
+          $cat->admin_title = $cat->title;
         }
-        $tree[] = $categories[$cnid][$child];
+        $tree[] = $cat;
 
         if ($children[$cnid][$child]) {
           $tree = array_merge($tree, category_get_tree($cnid, $child, $depth, $max_depth, $distant));
@@ -519,16 +520,16 @@ function category_next($cid) {
  *  - the output generated in visiting each node
  */
 function category_recurse($cid = 0, $depth = 1, $visit_pre, $visit_post, $export_type = NULL) {
-  $result = db_query(db_rewrite_sql('SELECT n.nid, n.title, c.weight FROM {node} n INNER JOIN {category} c ON n.nid = c.cid WHERE n.status = 1 AND n.moderate = 0 AND n.nid = %d ORDER BY c.weight, n.title'), $cid);
+  $result = db_query(db_rewrite_sql('SELECT n.nid, n.title, c.weight FROM {node} n INNER JOIN {category} c ON n.nid = c.cid WHERE n.status = 1 AND n.nid = %d ORDER BY c.weight, n.title'), $cid);
   while ($page = db_fetch_object($result)) {
     // Load the node:
     $node = node_load($page->nid);
     $type = category_node_get_type($node);
-    $is_cat = $type == 'category-cat';
+    $is_cat = $type == 'category_cat';
 
     if ($node) {
       if (!$is_cat && $node->hidden_cont) {
-        $children = db_query(db_rewrite_sql('SELECT n.nid, n.title, c.weight FROM {node} n INNER JOIN {category_hierarchy} h ON n.nid = h.cid INNER JOIN {category} c ON n.nid = c.cid INNER JOIN {node} n2 ON h.parent = n2.nid INNER JOIN {category} c2 ON h.parent = c2.cid WHERE n.status = 1 AND n.moderate = 0 AND h.parent = %d ORDER BY c.weight, n.title, c2.weight, n2.title'), $node->nid);
+        $children = db_query(db_rewrite_sql('SELECT n.nid, n.title, c.weight FROM {node} n INNER JOIN {category_hierarchy} h ON n.nid = h.cid INNER JOIN {category} c ON n.nid = c.cid INNER JOIN {node} n2 ON h.parent = n2.nid INNER JOIN {category} c2 ON h.parent = c2.cid WHERE n.status = 1 AND h.parent = %d ORDER BY c.weight, n.title, c2.weight, n2.title'), $node->nid);
         $cids = array();
         while ($childpage = db_fetch_object($children)) {
           if (!isset($cids[$childpage->nid])) {
@@ -549,7 +550,7 @@ function category_recurse($cid = 0, $dep
             $output .= category_node_visitor_html_pre($node, $depth, $cid);
           }
 
-          $children = db_query(db_rewrite_sql('SELECT n.nid, n.title, c.weight FROM {node} n INNER JOIN {category_hierarchy} h ON n.nid = h.cid INNER JOIN {category} c ON n.nid = c.cid INNER JOIN {node} n2 ON h.parent = n2.nid INNER JOIN {category} c2 ON h.parent = c2.cid WHERE n.status = 1 AND n.moderate = 0 AND h.parent = %d ORDER BY c.weight, n.title, c2.weight, n2.title'), $node->nid);
+          $children = db_query(db_rewrite_sql('SELECT n.nid, n.title, c.weight FROM {node} n INNER JOIN {category_hierarchy} h ON n.nid = h.cid INNER JOIN {category} c ON n.nid = c.cid INNER JOIN {node} n2 ON h.parent = n2.nid INNER JOIN {category} c2 ON h.parent = c2.cid WHERE n.status = 1 AND h.parent = %d ORDER BY c.weight, n.title, c2.weight, n2.title'), $node->nid);
           $cids = array();
           while ($childpage = db_fetch_object($children)) {
             if (!isset($cids[$childpage->nid])) {
@@ -576,11 +577,23 @@ function category_recurse($cid = 0, $dep
 }
 
 /**
+ * Implementation of hook_node_type().
+ */
+function category_node_type($op, $info) {
+  if ($op == 'update' && !empty($info->old_type) && $info->type != $info->old_type) {
+    db_query("UPDATE {category_cont_node_types} SET type = '%s' WHERE type = '%s'", $info->type, $info->old_type);
+  }
+  elseif ($op == 'delete') {
+    db_query("DELETE FROM {category_cont_node_types} WHERE type = '%s'", $info->type);
+  }
+}
+
+/**
  * Find all category objects related to a given category ID.
  */
 function category_get_related($cid, $key = 'cid') {
   if ($cid) {
-    $result = db_query(db_rewrite_sql('SELECT c.*, n.title, cid1, cid2 FROM {category_relation}, {category} c, {node} n WHERE (c.cid = cid1 OR c.cid = cid2) AND (cid1 = %d OR cid2 = %d) AND c.cid = n.nid AND c.cid != %d AND n.status = 1 AND n.moderate = 0 ORDER BY c.weight, n.title'), $cid, $cid, $cid);
+    $result = db_query(db_rewrite_sql('SELECT c.*, n.title, cid1, cid2 FROM {category_relation}, {category} c, {node} n WHERE (c.cid = cid1 OR c.cid = cid2) AND (cid1 = %d OR cid2 = %d) AND c.cid = n.nid AND c.cid != %d AND n.status = 1 ORDER BY c.weight, n.title'), $cid, $cid, $cid);
     $related = array();
     while ($category = db_fetch_object($result)) {
       $related[$category->$key] = $category;
@@ -729,11 +742,10 @@ function category_node_save(&$node, $is_
             $tag_node = new stdClass();
             $tag_node->title = $typed_cat;
             $tag_node->cnid = $cnid;
-            $tag_node->type = 'category-cat';
+            $tag_node->type = 'category_cat';
             $tag_node->parents[0] = $tag_node->parent = $cnid;
             $node_options = variable_get('node_options_'. $tag_node->type, array('status', 'promote'));
             $tag_node->status = in_array('status', $node_options);
-            $tag_node->moderate = in_array('moderate', $node_options);
             $tag_node->promote = in_array('promote', $node_options);
             $tag_node->sticky = in_array('sticky', $node_options);
             $tag_node->revision = in_array('revision', $node_options);
@@ -796,10 +808,10 @@ function category_category_count_nodes($
   if (!isset($count[$type])) {
     // $type == 0 always evaluates true if $type is a string
     if (is_numeric($type)) {
-      $result = db_query(db_rewrite_sql('SELECT c.cid, COUNT(n.nid) AS cnt FROM {category_node} c INNER JOIN {node} n ON c.nid = n.nid WHERE n.status = 1 AND n.moderate = 0 GROUP BY c.cid'));
+      $result = db_query(db_rewrite_sql('SELECT c.cid, COUNT(n.nid) AS cnt FROM {category_node} c INNER JOIN {node} n ON c.nid = n.nid WHERE n.status = 1 GROUP BY c.cid'));
     }
     else {
-      $result = db_query(db_rewrite_sql("SELECT c.cid, COUNT(n.nid) AS cnt FROM {category_node} c INNER JOIN {node} n ON c.nid = n.nid WHERE n.status = 1 AND n.moderate = 0 AND n.type = '%s' GROUP BY c.cid"), $type);
+      $result = db_query(db_rewrite_sql("SELECT c.cid, COUNT(n.nid) AS cnt FROM {category_node} c INNER JOIN {node} n ON c.nid = n.nid WHERE n.status = 1 AND n.type = '%s' GROUP BY c.cid"), $type);
     }
     while ($category = db_fetch_object($result)) {
       $count[$type][$category->cid] = $category->cnt;
@@ -818,7 +830,7 @@ function category_node_get_categories($n
   if (!isset($categories[$nid]) || $reset) {
     $categories[$nid] = array();
 
-    $result = db_query(db_rewrite_sql('SELECT n.nid, r.nid AS node_id, c.*, n.title FROM {category} c INNER JOIN {category_node} r ON c.cid = r.cid INNER JOIN {category} cn ON c.cnid = cn.cid INNER JOIN {node} n ON c.cid = n.nid INNER JOIN {node} cnn ON cn.cid = cnn.nid WHERE n.status = 1 AND n.moderate = 0 AND r.nid = %d ORDER BY cn.weight, cnn.title, c.weight, n.title'), $nid);
+    $result = db_query(db_rewrite_sql('SELECT n.nid, r.nid AS node_id, c.*, n.title FROM {category} c INNER JOIN {category_node} r ON c.cid = r.cid INNER JOIN {category} cn ON c.cnid = cn.cid INNER JOIN {node} n ON c.cid = n.nid INNER JOIN {node} cnn ON cn.cid = cnn.nid WHERE n.status = 1 AND r.nid = %d ORDER BY cn.weight, cnn.title, c.weight, n.title'), $nid);
 
     while ($category = db_fetch_object($result)) {
       $categories[$nid][$category->$key] = $category;
@@ -832,7 +844,7 @@ function category_node_get_categories($n
  * Find all categories associated to the given node, within one container.
  */
 function category_node_get_categories_by_container($nid, $cnid, $key = 'cid') {
-  $result = db_query(db_rewrite_sql('SELECT c.*, n.title FROM {category} c INNER JOIN {category_node} r ON c.cid = r.cid INNER JOIN {node} n ON c.cid = n.nid WHERE c.cnid = %d AND r.nid = %d AND n.status = 1 AND n.moderate = 0 ORDER BY c.weight'), $cnid, $nid);
+  $result = db_query(db_rewrite_sql('SELECT c.*, n.title FROM {category} c INNER JOIN {category_node} r ON c.cid = r.cid INNER JOIN {node} n ON c.cid = n.nid WHERE c.cnid = %d AND r.nid = %d AND n.status = 1 ORDER BY c.weight'), $cnid, $nid);
   $categories = array();
   while ($category = db_fetch_object($result)) {
     $categories[$category->$key] = $category;
@@ -891,8 +903,8 @@ function category_select_nodes($cids = a
     $group_by = 'n.nid, n.sticky, n.title, n.created';
     if ($operator == 'or') {
       $str_cids = implode(',', call_user_func_array('array_merge', $descendant_cids));
-      $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n INNER JOIN {category_node} cn ON n.nid = cn.nid WHERE cn.cid IN ('. $str_cids .') AND n.status = 1 AND n.moderate = 0 GROUP BY '. $group_by .' ORDER BY '. $order;
-      $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n INNER JOIN {category_node} cn ON n.nid = cn.nid WHERE cn.cid IN ('. $str_cids .') AND n.status = 1 AND n.moderate = 0';
+      $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n INNER JOIN {category_node} cn ON n.nid = cn.nid WHERE cn.cid IN ('. $str_cids .') AND n.status = 1 GROUP BY '. $group_by .' ORDER BY '. $order;
+      $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n INNER JOIN {category_node} cn ON n.nid = cn.nid WHERE cn.cid IN ('. $str_cids .') AND n.status = 1';
     }
     else {
       $joins = '';
@@ -901,8 +913,8 @@ function category_select_nodes($cids = a
         $joins .= ' INNER JOIN {category_node} cn'. $index .' ON n.nid = cn'. $index .'.nid';
         $wheres .= ' AND cn'. $index .'.cid IN ('. implode(',', $cids) .')';
       }
-      $sql = 'SELECT n.nid, n.sticky, n.title, n.created FROM {node} n '. $joins .' WHERE n.status = 1 AND n.moderate = 0 '. $wheres .' GROUP BY '. $group_by .' ORDER BY '. $order;
-      $sql_count = 'SELECT COUNT(n.nid) FROM {node} n '. $joins .' WHERE n.status = 1 AND n.moderate = 0 ' . $wheres;
+      $sql = 'SELECT n.nid, n.sticky, n.title, n.created FROM {node} n '. $joins .' WHERE n.status = 1 '. $wheres .' GROUP BY '. $group_by .' ORDER BY '. $order;
+      $sql_count = 'SELECT COUNT(n.nid) FROM {node} n '. $joins .' WHERE n.status = 1 ' . $wheres;
     }
     $sql = db_rewrite_sql($sql);
     $sql_count = db_rewrite_sql($sql_count);
@@ -966,7 +978,7 @@ function category_form_all($free_tags = 
     $options[$container->admin_title] = array();
     if ($tree) {
       foreach ($tree as $category) {
-        $options[$container->admin_title][$category->cid] = _category_depth($category->depth, '-') . $category->title;
+        $options[$container->admin_title][$category->cid] = str_repeat('-', $category->depth) . $category->title;
       }
     }
   }
@@ -987,13 +999,38 @@ function category_render_nodes($result) 
     $output .= theme('pager', NULL, variable_get('default_nodes_main', 10), 0);
   }
   else {
-    $output .= t('There are currently no posts in this category.');
+    $output .= '<p>'. t('There are currently no posts in this category.') .'</p>';
   }
 
   return $output;
 }
 
 /**
+ * Parses a comma or plus separated string of category IDs.
+ *
+ * @param $str_cids
+ *   A string of category IDs, separated by plus or comma.
+ *   comma (,) means AND
+ *   plus (+) means OR
+ *
+ * @return an associative array with an operator key (either 'and'
+ *   or 'or') and a cid key containing an array of the category IDs.
+ */
+function category_categories_parse_string($str_cids) {
+  $categories = array();
+  if (preg_match('/^([0-9]+[+ ])+[0-9]+$/', $str_cids)) {
+    $categories['operator'] = 'or';
+    // The '+' character in a query string may be parsed as ' '.
+    $categories['cids'] = preg_split('/[+ ]/', $str_cids);
+  }
+  else if (preg_match('/^([0-9]+,)*[0-9]+$/', $str_cids)) {
+    $categories['operator'] = 'and';
+    $categories['cids'] = explode(',', $str_cids);
+  }
+  return $categories;
+}
+
+/**
  * Generates various representation of a cateogry page with
  * all descendants and prints the requested representation to output.
  *
@@ -1064,7 +1101,7 @@ function category_get_form($is_cat = TRU
 
     $body_text = '';
     if (isset($node->body)) {
-      if (!(module_exist('category_display') && $node->body_is_desc)) {
+      if (!(module_exists('category_display') && $node->body_is_desc)) {
         $body_text = $node->body;
       }
     }
@@ -1099,7 +1136,7 @@ function category_get_form($is_cat = TRU
     '#description' => ($is_cat ? t('A description of the category. Generally seen by users as title text, when hovering over a link to the category.') : t('A description of the container; can be used by modules.')),
   );
 
-  $activeselect = module_exist('activeselect');
+  $activeselect = module_exists('activeselect');
   $activeselect_type = ($activeselect ? 'activeselect' : 'select');
 
   if ($is_cat) {
@@ -1159,7 +1196,7 @@ function category_get_form($is_cat = TRU
       '#type' => 'checkboxes',
       '#title' => t('Types'),
       '#default_value' => $node->nodes ? $node->nodes : array(),
-      '#options' => node_get_types(),
+      '#options' => node_get_types('names'),
       '#description' => t('A list of node types you want to associate with categories in this container.'),
     );
     $form['catinfo']['hierarchy'] = array(
@@ -1167,20 +1204,20 @@ function category_get_form($is_cat = TRU
       '#title' => t('Hierarchy'),
       '#default_value' => isset($node->hierarchy) ? $node->hierarchy : 1,
       '#options' => array(0 => t('Disabled'), 1 => t('Single'), 2 => t('Multiple')),
-      '#description' => t('Allows <a href="%help-url">a tree-like hierarchy</a> between categories within a container. Depending on your distant parent configuration, this may also allow a hierarchy between categories and containers regardless of their parent container. Be aware that the <em>multiple</em> option refers to multiple parents, as opposed to multiple levels of hierarchy.', array('%help-url' => url('admin/help/category', NULL, 'hierarchy'))),
+      '#description' => t('Allows <a href="!help-url">a tree-like hierarchy</a> between categories within a container. Depending on your distant parent configuration, this may also allow a hierarchy between categories and containers regardless of their parent container. Be aware that the <em>multiple</em> option refers to multiple parents, as opposed to multiple levels of hierarchy.', array('!help-url' => url('admin/help/category', NULL, 'hierarchy'))),
       '#required' => TRUE,
     );
     $form['catinfo']['has_relations'] = array(
       '#type' => 'checkbox',
       '#title' => t('Related terms'),
       '#default_value' => isset($node->has_relations) ? $node->has_relations : 0,
-      '#description' => t('Allows <a href="%help-url">relations</a> between arbitrary categories or containers.', array('%help-url' => url('admin/help/category'))),
+      '#description' => t('Allows <a href="!help-url">relations</a> between arbitrary categories or containers.', array('!help-url' => url('admin/help/category'))),
     );
     $form['catinfo']['has_synonyms'] = array(
       '#type' => 'checkbox',
       '#title' => t('Synonyms'),
       '#default_value' => isset($node->has_synonyms) ? $node->has_synonyms : 0,
-      '#description' => t('Allows <a href="%help-url">synonyms</a> for a category or container, such as misspellings and acronyms.', array('%help-url' => url('admin/help/category'))),
+      '#description' => t('Allows <a href="!help-url">synonyms</a> for a category or container, such as misspellings and acronyms.', array('!help-url' => url('admin/help/category'))),
     );
     $form['catinfo']['tags'] = array(
       '#type' => 'checkbox',
@@ -1250,7 +1287,7 @@ function category_get_form($is_cat = TRU
   if ($hierarchy == 1 || $activeselect) {
     $form['catinfo']['parents'] = _category_category_select(t('Parent'), $parents, $default_parent, t('Parent category or container. Containers are marked with an asterisk (*).'), 0, $blank, $exclude);
   }
-	elseif ($hierarchy == 2) {
+  elseif ($hierarchy == 2) {
     $form['catinfo']['parents'] = _category_category_select(t('Parents'), $parents, $default_parent, t('Parent categories or containers. Containers are marked with an asterisk (*).'), ($activeselect ? 0 : 1), $blank, $exclude);
   }
 
@@ -1359,13 +1396,13 @@ function category_get_wrapper_status($ty
   static $taxonomy_status, $book_status;
 
   if (!isset($taxonomy_status)) {
-    $taxonomy_status = module_exist('taxonomy') && !menu_get_item(NULL, 'admin/taxonomy');
+    $taxonomy_status = module_exists('taxonomy') && !menu_get_item(NULL, 'admin/content/taxonomy');
     if ($check_db) {
       $taxonomy_status = $taxonomy_status && variable_get('taxonomy_maintain_db', 1);
     }
   }
   if (!isset($book_status)) {
-    $book_status = module_exist('book') && !menu_get_item(NULL, 'admin/node/book');
+    $book_status = module_exists('book') && !menu_get_item(NULL, 'admin/content/book');
     if ($check_db) {
       $book_status = $book_status && variable_get('book_maintain_db', 1);
     }
@@ -1493,15 +1530,6 @@ function _category_get_depth($cid) {
   }
 }
 
-function _category_depth($depth, $graphic = '--') {
-  for ($n = 0; $n < $depth; $n++) {
-    $result .= $graphic;
-  }
-  return $result;
-}
-
-
-
 /**
  * Helper for category_category_count_nodes().
  */
Index: category.info
===================================================================
RCS file: category.info
diff -N category.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ category.info	5 Jan 2007 15:20:47 -0000
@@ -0,0 +1,4 @@
+; $Id$
+name = Category
+description = Allows you to structure your site and categorize content.
+package = Category
Index: category.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/category/category.install,v
retrieving revision 1.10
diff -u -p -r1.10 category.install
--- category.install	14 Apr 2006 13:52:03 -0000	1.10
+++ category.install	5 Jan 2007 15:20:47 -0000
@@ -204,3 +204,67 @@ function category_update_8() {
 
   return $ret;
 }
+
+/**
+ * Drupal 5.0 updates
+ */
+function category_update_9() {
+  // Node types may no longer contain hyphens.
+  $ret[] = update_sql("UPDATE {node} SET type = 'category_cat' WHERE type = 'category-cat'");
+  $ret[] = update_sql("UPDATE {node} SET type = 'category_cont' WHERE type = 'category-cont'");
+
+  // Some of our variables need to be renamed.
+  $result = db_query("SELECT name FROM {variable} WHERE name LIKE 'category_nodeapi_%_containers'");
+  while ($row = db_fetch_array($result)) {
+    // Determine the new name of the variable
+    $name = str_replace('-', '_', preg_replace('/^category_nodeapi_(.*)_containers$/U','category_nodeapi_containers_$1', $row['name']));
+    // Change the name.
+    $ret[] = update_sql("UPDATE {variable} SET name = '". db_escape_string($name) ."' WHERE name = '". db_escape_string($row['name']) ."'");
+  }
+
+  // Some more similar variable renaming.
+  $result = db_query("SELECT name, value FROM {variable} WHERE name LIKE 'category_nodeapi_%' AND name NOT LIKE 'category_nodeapi_containers_%'");
+  while ($row = db_fetch_array($result)) {
+    // Determine the new name of the variable
+    $name = str_replace('-', '_', $row['name']);
+    $value = str_replace('-', '_', $row['value']);
+    // Change the name.
+    $ret[] = update_sql("UPDATE {variable} SET name = '". db_escape_string($name) ."', value = '". db_escape_string($value) ."' WHERE name = '". db_escape_string($row['name']) ."'");
+  }
+
+  cache_clear_all();
+
+  // Update the keys of the 'category_allow_nodetypes' variable.
+  $allow_nodetypes = variable_get('category_allow_nodetypes', array('category_cat' => 0, 'category_cont' => 0));
+  foreach ($allow_nodetypes as $nodetype => $val) {
+    if (strpos($nodetype, '-') !== FALSE) {
+      $new_nodetype = str_replace('-', '_', $nodetype);
+      if ($nodetype === $val) {
+        $allow_nodetypes[$new_nodetype] = $new_nodetype;
+      }
+      else {
+        $allow_nodetypes[$new_nodetype] = $val;
+      }
+      unset($allow_nodetypes[$nodetype]);
+    }
+  }
+  variable_set('category_allow_nodetypes', $allow_nodetypes);
+
+  // Update the keys and values of the 'category_base_nodetypes' variable.
+  $base_nodetypes = variable_get('category_base_nodetypes', array('category_cat' => 'category_cat', 'category_cont' => 'category_cont'));
+  foreach ($base_nodetypes as $nodetype => $val) {
+    if (strpos($nodetype, '-') !== FALSE) {
+      $new_nodetype = str_replace('-', '_', $nodetype);
+      if ($nodetype === $val) {
+        $base_nodetypes[$new_nodetype] = $new_nodetype;
+      }
+      else {
+        $base_nodetypes[$new_nodetype] = $val;
+      }
+      unset($base_nodetypes[$nodetype]);
+    }
+  }
+  variable_set('category_base_nodetypes', $base_nodetypes);
+
+  return $ret;
+}
Index: category.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/category/category.module,v
retrieving revision 1.123
diff -u -p -r1.123 category.module
--- category.module	24 Nov 2006 05:22:31 -0000	1.123
+++ category.module	5 Jan 2007 15:20:49 -0000
@@ -6,23 +6,19 @@
  * Allows users to structure their site and organize content with categories.
  */
 
+require_once dirname(drupal_get_filename('module', 'category')) . '/category.inc';
+
 /**
  * Implementation of hook_help().
  */
 function category_help($section) {
   switch ($section) {
-    case 'admin/modules#description':
-      return t('Allows you to structure your site and categorize content.');
-    case 'admin/category':
+    case 'admin/content/category':
       return t('<p>The category module allows you to structure your site and to categorize content: you can create multiple containers (types of categorizations) that contain a tree of categories; you can assign content to your categories; and you can give your categories their own content (such as a description).</p>');
     case 'admin/help#category':
       return t('<p>The category module allows you to structure your site and to categorize content: you can create multiple containers (types of categorizations) that contain a tree of categories; you can assign content to your categories; and you can give your categories their own content (such as a description).</p>');
-    case 'node/add#category-cat':
-      return t("Categories are used to structure your site, and to categorize content. You can create a category as the child of a container, or of another category. You can assign content to one or more categories.");
-    case 'node/add#category-cont':
-      return t("A container is usually the root of a category tree, but can also be created as the child of another container, or of a category. Containers are used for describing a particular way of classifying content.");
-    case 'admin/settings/category':
-      return t('<p>Settings controlling the behaviour of categories and containers on this site. As well as settings for the category module itself, settings for other modules in the category package can also be configured here. Only global settings are controlled here: most settings are controlled on a per-container or per-category basis, and are instead configured on the add/edit category/container pages. See the <a href="%category">categories</a> page for actual categories and containers.</p>', array('%category' => url('admin/category')));
+    case 'admin/content/category/settings':
+      return t('<p>Settings controlling the behaviour of categories and containers on this site. As well as settings for the category module itself, settings for other modules in the category package can also be configured here. Only global settings are controlled here: most settings are controlled on a per-container or per-category basis, and are instead configured on the add/edit category/container pages. See the <a href="!category">list</a> page for actual categories and containers.</p>', array('!category' => url('admin/content/category')));
   }
 }
 
@@ -30,14 +26,22 @@ function category_help($section) {
  * Implementation of hook_node_info().
  */
 function category_node_info() {
-  $base_types = variable_get('category_base_nodetypes', array('category-cat' => 'category-cat', 'category-cont' => 'category-cont'));
+  $base_types = variable_get('category_base_nodetypes', array('category_cat' => 'category_cat', 'category_cont' => 'category_cont'));
   $types_list = array();
 
-  if ($base_types['category-cont']) {
-    $types_list['category-cont'] = array('name' => t('container'), 'base' => 'category');
+  if ($base_types['category_cont']) {
+    $types_list['category_cont'] = array(
+      'name' => t('Container'),
+      'module' => 'category',
+      'description' => t("A container is usually the root of a category tree, but can also be created as the child of another container, or of a category. Containers are used for describing a particular way of classifying content."),
+    );
   }
-  if ($base_types['category-cat']) {
-    $types_list['category-cat'] = array('name' => t('category'), 'base' => 'category');
+  if ($base_types['category_cat']) {
+    $types_list['category_cat'] = array(
+      'name' => t('Category'),
+      'module' => 'category',
+      'description' => t("Categories are used to structure your site, and to categorize content. You can create a category as the child of a container, or of another category. You can assign content to one or more categories."),
+    );
   }
 
   return $types_list;
@@ -47,16 +51,16 @@ function category_node_info() {
  * Implementation of hook_perm().
  */
 function category_perm() {
-  $base_types = variable_get('category_base_nodetypes', array('category-cat' => 'category-cat', 'category-cont' => 'category-cont'));
+  $base_types = variable_get('category_base_nodetypes', array('category_cat' => 'category_cat', 'category_cont' => 'category_cont'));
   $perms_list = array();
 
-  if ($base_types['category-cat']) {
+  if ($base_types['category_cat']) {
     $perms_list[] = 'create categories';
   }
-  if ($base_types['category-cont']) {
+  if ($base_types['category_cont']) {
     $perms_list[] = 'create containers';
   }
-  if ($base_types['category-cat'] || $base_types['category-cont']) {
+  if ($base_types['category_cat'] || $base_types['category_cont']) {
     $perms_list[] = 'edit all categories';
     $perms_list[] = 'edit own categories';
   }
@@ -66,11 +70,14 @@ function category_perm() {
 }
 
 /**
- * Implementation of hook_init().
- *
+ * Implementation of hook_enable().
  */
-function category_init() {
-  require_once dirname(drupal_get_filename('module', 'category')) . '/category.inc';
+function category_enable() {
+  foreach (array('book', 'taxonomy') as $type) {
+    if (module_exists($type) && !category_get_wrapper_status($type)) {
+      category_wrapper($type, 'install', 'admin/build/modules', FALSE);
+    }
+  }
 }
 
 /**
@@ -78,12 +85,12 @@ function category_init() {
  */
 function category_menu($may_cache) {
   $items = array();
-  $base_types = variable_get('category_base_nodetypes', array('category-cat' => 'category-cat', 'category-cont' => 'category-cont'));
+  $base_types = variable_get('category_base_nodetypes', array('category_cat' => 'category_cat', 'category_cont' => 'category_cont'));
 
   if ($may_cache) {
     $items[] = array(
       'path' => 'category',
-      'title' => t('categories'),
+      'title' => t('Categories'),
       'callback' => 'category_category_page',
       'access' => user_access('access content'),
       'type' => MENU_CALLBACK,
@@ -94,71 +101,67 @@ function category_menu($may_cache) {
       'access' => user_access('access content'),
       'type' => MENU_CALLBACK);
     $items[] = array(
-      'path' => 'admin/category',
-      'title' => t('categories'),
+      'path' => 'admin/content/category',
+      'title' => t('Categories'),
+      'description' => t('Create containers and categories to categorize your content.'),
       'callback' => 'category_admin',
       'access' => user_access('administer categories'),
     );
     $items[] = array(
-      'path' => 'admin/category/list',
-      'title' => t('list'),
+      'path' => 'admin/content/category/list',
+      'title' => t('List'),
       'type' => MENU_DEFAULT_LOCAL_TASK,
       'weight' => -10,
     );
     $items[] = array(
-      'path' => 'admin/category/list/container',
-      'title' => t('containers'),
+      'path' => 'admin/content/category/list/container',
+      'title' => t('Containers'),
       'type' => MENU_DEFAULT_LOCAL_TASK,
       'weight' => -10,
     );
     $items[] = array(
-      'path' => 'admin/category/add',
-      'title' => t('add container'),
+      'path' => 'admin/content/category/add',
+      'title' => t('Add container'),
       'callback' => 'category_admin',
       'access' => user_access('administer categories'),
       'type' => MENU_LOCAL_TASK,
       'weight' => -6,
     );
-    if ($base_types['category-cat']) {
-      $items[] = array(
-        'path' => 'node/add/category-cat',
-        'title' => t('category'),
-        'access' => _category_privileged('create categories'),
-      );
-    }
-    if ($base_types['category-cont']) {
-      $items[] = array(
-        'path' => 'node/add/category-cont',
-        'title' => t('container'),
-        'access' => _category_privileged('create containers'),
-      );
-    }
+    $items[] = array(
+      'path' => 'admin/content/category/settings',
+      'title' => t('Settings'),
+      'callback' => 'drupal_get_form',
+      'callback arguments' => 'category_admin_settings',
+      'access' => user_access('administer categories'),
+      'type' => MENU_LOCAL_TASK,
+      'weight' => -3,
+     );
     $items[] = array('path' => 'category/autocomplete',
-      'title' => t('autocomplete category'),
+      'title' => t('Autocomplete category'),
       'callback' => 'category_autocomplete',
       'access' => user_access('access content'),
       'type' => MENU_CALLBACK,
     );
     $items[] = array('path' => 'category/activeselect',
-      'title' => t('activeselect category'),
+      'title' => t('Activeselect category'),
       'callback' => 'category_activeselect',
       'access' => user_access('access content'),
       'type' => MENU_CALLBACK,
     );
     $items[] = array('path' => 'category/wrapper',
-      'title' => t('category wrappers'),
+      'title' => t('Category wrappers'),
       'callback' => 'category_wrapper',
       'access' => user_access('administer site configuration'),
       'type' => MENU_CALLBACK,
     );
   }
   else {
-    if (arg(0) == 'admin' && arg(1) == 'category' && is_numeric(arg(2))) {
-      $nid = arg(2);
+    if (arg(0) == 'admin' && arg(1) == 'content' && arg(2) == 'category' && is_numeric(arg(3))) {
+      $nid = arg(3);
       $node = node_load($nid);
 
       $items[] = array(
-        'path' => 'admin/category/' . $nid,
+        'path' => 'admin/content/category/' . $nid,
         'title' => $node->admin_title,
         'callback' => 'category_admin',
         'access' => user_access('administer categories'),
@@ -166,22 +169,22 @@ function category_menu($may_cache) {
       );
 
       $items[] = array(
-        'path' => 'admin/category/' . $nid . '/list',
-        'title' => t('list'),
+        'path' => 'admin/content/category/' . $nid . '/list',
+        'title' => t('List'),
         'type' => MENU_DEFAULT_LOCAL_TASK,
         'weight' => -10,
       );
 
       $items[] = array(
-        'path' => 'admin/category/' . $nid . '/list/category',
-        'title' => t('categories'),
+        'path' => 'admin/content/category/' . $nid . '/list/category',
+        'title' => t('Categories'),
         'type' => MENU_DEFAULT_LOCAL_TASK,
         'weight' => -10,
       );
 
       $items[] = array(
-        'path' => 'admin/category/' . $nid . '/add',
-        'title' => t('add category'),
+        'path' => 'admin/content/category/' . $nid . '/add',
+        'title' => t('Add category'),
         'callback' => 'category_admin',
         'access' => user_access('administer categories'),
         'type' => MENU_LOCAL_TASK,
@@ -194,7 +197,7 @@ function category_menu($may_cache) {
       if ($is_cat) {
         $items[] = array(
           'path' => "node/$nid/feed",
-          'title' => t('feed'),
+          'title' => t('Feed'),
           'callback' => 'category_feed',
           'type' => MENU_CALLBACK,
         );
@@ -213,7 +216,7 @@ function category_access($op, $node) {
 
   if ($op == 'create') {
     $type = $node;
-    if ($type == 'category-cont') {
+    if ($type == 'category_cont') {
       return _category_privileged('create containers');
     }
     else {
@@ -228,7 +231,7 @@ function category_access($op, $node) {
     // of that page waiting for approval.  That is, only updates that
     // don't overwrite the current or pending information are allowed.
 
-    if ((_category_privileged('edit all') && !$node->moderate) || ($node->uid == $user->uid && user_access('edit own categories'))) {
+    if (_category_privileged('edit all') || ($node->uid == $user->uid && user_access('edit own categories'))) {
       return TRUE;
     }
     else {
@@ -244,20 +247,26 @@ function category_access($op, $node) {
  * print lists of categories associated with a node. Themes can print category
  * links with:
  *
- * if (module_exist('category')) {
+ * if (module_exists('category')) {
  *   $this->links(category_link('categories', $node));
  * }
  */
-function category_link($type, $node = NULL, $main = NULL) {
+function category_link($type, $node = NULL, $teaser = FALSE) {
   $links = array();
 
   if ($type == 'node' && isset($node->parents)) {
-    if (!$main && ($node->type != 'category-cat' || $node->hierarchy)) {
+    if (!$teaser && ($node->type != 'category_cat' || $node->hierarchy)) {
       if (_category_privileged('create categories')) {
-        $links[] = l(t('add child category'), "node/add/category-cat/parent/$node->nid");
+        $links['category_add_category'] = array(
+          'title' => t('Add child category'),
+          'href' => "node/add/category-cat/parent/$node->nid",
+        );
       }
       if (_category_privileged('create containers')) {
-        $links[] = l(t('add child container'), "node/add/category-cont/parent/$node->nid");
+        $links['category_add_container'] = array(
+          'title' => t('Add child container'),
+          'href' => "node/add/category-cont/parent/$node->nid",
+        );
       }
     }
   }
@@ -266,8 +275,12 @@ function category_link($type, $node = NU
     $links = array();
     if (isset($node->category) && is_array($node->category)) {
       foreach ($node->category as $category) {
-        if (!module_exist('category_display') || ($category->cid && ($cat_node = node_load($category->cid)) && $cat_node->nodelinks)) {
-          $links[] = l($category->title, category_category_path($category), array('rel' => 'tag', 'title' => strip_tags($category->description)));
+        if (!module_exists('category_display') || ($category->cid && ($cat_node = node_load($category->cid)) && $cat_node->nodelinks)) {
+          $links['category_cat_'. $category->cid] = array(
+            'title' => $category->title,
+            'href' => category_category_path($category),
+            'attributes' => array('rel' => 'tag', 'title' => strip_tags($category->description)),
+          );
         }
       }
     }
@@ -277,9 +290,9 @@ function category_link($type, $node = NU
 }
 
 /**
- * Implementation of hook_settings().
+ * Settings form.
  */
-function category_settings() {
+function category_admin_settings() {
   $form = array();
   // select options
   $distant = array(
@@ -306,7 +319,9 @@ function category_settings() {
     '#type' => 'item',
     '#title' => t('Taxonomy wrapper status'),
     '#value' => theme('category_wrapper_status', 'taxonomy', $taxonomy_status),
-    '#description' => '<p>'. t('You can install and uninstall the taxonomy and book wrapper modules using the links below. It is very important that you have taxonomy or book (original or wrapper, whichever is installed) <strong>enabled</strong> on the %module-admin-page before performing an install or uninstall. Additionally, you should make sure that your web server has write permission on the file system, or the scripts may be denied access to copy and rename the necessary files.', array('%module-admin-page' => l(t('module administration page'), 'admin/modules'))). '</p><p>'. t('When performing an install, the scripts will rename your existing taxonomy or book module file to <code>modulename.module.old</code>. It will then copy the appropriate <code>modulename.module.copyme</code> file from the <code>wrappers/</code> directory (in your category package) to the location where the old module file was, and will rename the copied file to <code>modulename.module</code>. The reverse will happen when performing an uninstall. The script will determine the correct location of all necessary files automatically, based on the existing locations of those files.'). '</p><p>'. t('After the operation that you invoke is completed, you will be returned to this page.'). '</p>',
+    '#description' => '<p>'. t('You can install and uninstall the taxonomy and book wrapper modules using the links below. It is very important that you have taxonomy or book (original or wrapper, whichever is installed) <strong>enabled</strong> on the <a href="!module-admin-page">module administration page</a> before performing an install or uninstall. Additionally, you should make sure that your web server has write permission on the file system, or the scripts may be denied access to copy and rename the necessary files.', array('!module-admin-page' => url('admin/build/modules'))) .'</p>'
+    .'<p>'. t('When performing an install, the scripts will rename your existing taxonomy or book module file to <code>modulename.module.old</code>. It will then copy the appropriate <code>modulename.module.copyme</code> file from the <code>wrappers/</code> directory (in your category package) to the location where the old module file was, and will rename the copied file to <code>modulename.module</code>. The reverse will happen when performing an uninstall. The script will determine the correct location of all necessary files automatically, based on the existing locations of those files.') .'</p>'
+    .'<p>'. t('After the operation that you invoke is completed, you will be returned to this page.') .'</p>',
   );
 
   // Node type settings
@@ -319,15 +334,15 @@ function category_settings() {
   $form['nodetype']['category_allow_nodetypes'] = array(
     '#type' => 'checkboxes',
     '#title' => t('Allow other content types to be'),
-    '#default_value' =>  variable_get('category_allow_nodetypes', array('category-cat' => 0, 'category-cont' => 0)),
-    '#options' => array('category-cat' => t('Categories'), 'category-cont' => t('Containers')),
+    '#default_value' =>  variable_get('category_allow_nodetypes', array('category_cat' => 0, 'category_cont' => 0)),
+    '#options' => array('category_cat' => t('Categories'), 'category_cont' => t('Containers')),
     '#description' => t('Allows category or container behavior to be assigned to other content types. When enabled, each content type (except for category and container) receives a new setting allowing it to be a category or a container. When switched on for a particular content type, all nodes of that type receive the new behavior.')
   );
   $form['nodetype']['category_base_nodetypes'] = array(
     '#type' => 'checkboxes',
     '#title' => t('Provide these content types'),
-    '#default_value' =>  variable_get('category_base_nodetypes', array('category-cat' => 'category-cat', 'category-cont' => 'category-cont')),
-    '#options' => array('category-cat' => t('Category'), 'category-cont' => t('Container')),
+    '#default_value' =>  variable_get('category_base_nodetypes', array('category_cat' => 'category_cat', 'category_cont' => 'category_cont')),
+    '#options' => array('category_cat' => t('Category'), 'category_cont' => t('Container')),
     '#description' => t('Provides a built-in content type for creating categories, and a built-in content type for creating containers. Do not disable either of these unless you have allowed other content types to be categories or containers, and you have set other content types to have category or container behavior; otherwise, you will have not be able to create categories or containers.')
   );
 
@@ -356,7 +371,7 @@ function category_settings() {
 
   $form['buttons']['#weight'] = 10;
 
-  return $form;
+  return system_settings_form($form);
 }
 
 /**
@@ -366,7 +381,7 @@ function category_load($node, $type = NU
   global $user;
 
   $type = category_node_get_type($node, $type);
-  $is_cat = $type == 'category-cat';
+  $is_cat = $type == 'category_cat';
 
   $category = category_get_category($node->nid);
   unset($category->cid);
@@ -437,7 +452,7 @@ function category_update($node, $type = 
   $node->module = $node->module ? $node->module : 'category';
 
   $type = category_node_get_type($node, $type);
-  $is_cat = $type == 'category-cat';
+  $is_cat = $type == 'category_cat';
 
   $data_exists = (db_result(db_query('SELECT COUNT(*) FROM {category} WHERE cid = %d', $node->nid)) > 0);
   if ($data_exists) {
@@ -528,7 +543,7 @@ function category_update($node, $type = 
  */
 function category_delete(&$node, $type = NULL) {
   $type = category_node_get_type($node, $type);
-  $is_cat = $type == 'category-cat';
+  $is_cat = $type == 'category_cat';
 
   db_query('DELETE FROM {category} WHERE cid = %d', $node->nid);
   db_query('DELETE FROM {category_hierarchy} WHERE cid = %d', $node->nid);
@@ -551,7 +566,7 @@ function category_delete(&$node, $type =
  */
 function category_form(&$node) {
   $parent_cont = arg(4);
-  $is_cat = $node->type == 'category-cat';
+  $is_cat = $node->type == 'category_cat';
 
   if (is_numeric($parent_cont)) {
     $category = category_get_category($parent_cont);
@@ -597,7 +612,7 @@ function category_category_legacy($op, &
   switch ($op) {
     case 'import_taxonomy_form':
     case 'import_book_form':
-      $note = '<em>'. t('Note:') .'</em>';
+      $note = t('Note:');
 
       unset($items['catinfo']['description']);
       unset($items['catinfo']['cnid']);
@@ -606,7 +621,7 @@ function category_category_legacy($op, &
       unset($items['catinfo']['weight']);
       unset($items['catinfo']['depth']);
 
-      $items['catinfo']['parents']['#description'] .= '<br/>'. t('%note this setting only affects containers. Categories retain the parents that they had as %former-self.', array('%note' => $note, '%former-self' => (($op == 'import_taxonomy_form') ? t('taxonomy terms') : t('book pages'))));
+      $items['catinfo']['parents']['#description'] .= '<br/>'. t('%note this setting only affects containers. Categories retain the parents that they had as @former-self.', array('%note' => $note, '@former-self' => (($op == 'import_taxonomy_form') ? t('taxonomy terms') : t('book pages'))));
 
       $items['catinfo']['depth_cont'] = array(
         '#type' => 'weight',
@@ -703,7 +718,7 @@ function category_submit(&$node) {
   $node->parents = array_values($node->parents);
 
   if (!isset($node->parents[0])) {
-    if ($node->type == 'category-cat') {
+    if ($node->type == 'category_cat') {
       $node->parents[0] = $node->parent = $node->cnid;
     }
     else {
@@ -729,12 +744,12 @@ function category_submit(&$node) {
 function category_admin() {
   // Special case for our "add category" menu localtask. this covers
   // the use of the "add category" LOCAL_TASK on a "view categories" page.
-  if (is_numeric(arg(2)) && arg(3) == 'add') {
-    drupal_goto('node/add/category-cat/parent/'. arg(2));
+  if (is_numeric(arg(3)) && arg(4) == 'add') {
+    drupal_goto('node/add/category-cat/parent/'. arg(3));
   }
   // Another special case for the "add container" menu localtask.
-  elseif (arg(2) == 'add') {
-    $destination = 'destination=admin/category';
+  elseif (arg(3) == 'add') {
+    $destination = 'destination=admin/content/category';
     drupal_goto('node/add/category-cont', $destination);
   }
 
@@ -746,8 +761,8 @@ function category_admin() {
  * containers and categories.
  */
 function category_overview() {
-  drupal_set_html_head(theme('stylesheet_import', base_path() . drupal_get_path('module', 'category') .'/category.css'));
-  $cnid = arg(2);
+  drupal_add_css(drupal_get_path('module', 'category') .'/category.css');
+  $cnid = arg(3);
   $destination = drupal_get_destination();
 
   $start_from      = $_GET['page'] ? $_GET['page'] : 0;
@@ -768,7 +783,7 @@ function category_overview() {
     }
     $containers = category_get_containers();
     foreach ($containers as $container) {
-      if (!$container->status || $container->moderate) {
+      if (!$container->status) {
         continue;
       }
 
@@ -781,7 +796,7 @@ function category_overview() {
       if (is_array($container->nodes)) {
         foreach ($container->nodes as $key => $type) {
           if ($type) {
-            $node_type = node_get_name($type);
+            $node_type = node_get_types('name', $type);
             $types[] = $node_type ? $node_type : $type;
           }
         }
@@ -801,10 +816,10 @@ function category_overview() {
 
       $none = theme('placeholder', t('none'));
       if ($colspan == 5) {
-        $rows[] = array(l($container->admin_title, "node/$container->cid"), (!empty($types) ? implode(', ', $types) : $none), l(t('edit container'), "node/$container->cid/edit", array(), $destination), l(t('list categories'), "admin/category/$container->cid"), l(t('add categories'), "admin/category/$container->cid/add"));
+        $rows[] = array(l($container->admin_title, "node/$container->cid"), (!empty($types) ? implode(', ', $types) : $none), l(t('edit container'), "node/$container->cid/edit", array(), $destination), l(t('list categories'), "admin/content/category/$container->cid"), l(t('add categories'), "admin/content/category/$container->cid/add"));
       }
       else {
-        $rows[] = array(l($container->admin_title, "node/$container->cid"), (!empty($types) ? implode(', ', $types) : $none), (!empty($parents) ? implode(', ', $parents) : $none), l(t('edit container'), "node/$container->cid/edit", array(), $destination), l(t('list categories'), "admin/category/$container->cid"), l(t('add categories'), "admin/category/$container->cid/add"));
+        $rows[] = array(l($container->admin_title, "node/$container->cid"), (!empty($types) ? implode(', ', $types) : $none), (!empty($parents) ? implode(', ', $parents) : $none), l(t('edit container'), "node/$container->cid/edit", array(), $destination), l(t('list categories'), "admin/content/category/$container->cid"), l(t('add categories'), "admin/content/category/$container->cid/add"));
       }
 
       $displayed_count++; // we're counting containers displayed
@@ -867,10 +882,10 @@ function category_overview() {
 
       $none = theme('placeholder', t('none'));
       if ($colspan == 2) {
-        $rows[] = array(_category_depth($category->depth) . ' ' . l($category->title, "node/$category->cid"), l(t('edit'), "node/$category->cid/edit", array(), $destination));
+        $rows[] = array(str_repeat('-', $category->depth) . ' ' . l($category->title, "node/$category->cid"), l(t('edit'), "node/$category->cid/edit", array(), $destination));
       }
       else {
-        $rows[] = array(_category_depth($category->depth) . ' ' . l($category->title, "node/$category->cid"), (!empty($parents) ? implode(', ', $parents) : $none), l(t('edit'), "node/$category->cid/edit", array(), $destination));
+        $rows[] = array(str_repeat('-', $category->depth) . ' ' . l($category->title, "node/$category->cid"), (!empty($parents) ? implode(', ', $parents) : $none), l(t('edit'), "node/$category->cid/edit", array(), $destination));
       }
       $displayed_count++; // we're counting categories displayed
     }
@@ -897,7 +912,7 @@ function category_nodeapi(&$node, $op, $
   switch ($op) {
     case 'load':
       $node->category = category_node_get_categories($node->nid);
-      if ($node->type != 'category-cat' && $node->type != 'category-cont' && category_is_cat_or_cont($node->nid)) {
+      if ($node->type != 'category_cat' && $node->type != 'category_cont' && category_is_cat_or_cont($node->nid)) {
         $extra = category_load($node);
         foreach ($extra as $key => $value) {
           $node->$key = $value;
@@ -920,7 +935,7 @@ function category_nodeapi(&$node, $op, $
         'update' => t('Update category outline'),
         'delete' => t('Remove from category outline'),
       );
-      $type = category_node_get_type($node, arg(2));
+      $type = category_node_get_type($node, arg(3));
       if (in_array($op, $submit_values)) {
         switch ($op) {
           case $submit_values['insert']:
@@ -950,7 +965,7 @@ function category_nodeapi(&$node, $op, $
   	  return category_node_update_index($node);
     case 'view':
       if (!$teaser && category_is_cat_or_cont($node->nid)) {
-        $node->body = theme('category_view', $node);
+        $node->content += theme('category_view', $node);
       }
       break;
   }
@@ -1004,20 +1019,21 @@ function category_form_alter($form_id, &
 
   switch ($form_id) {
     // node settings form
-    case $type .'_node_settings':
-      if ($type != 'category-cont') {
-        $allow_types = variable_get('category_allow_nodetypes', array('category-cat' => 0, 'category-cont' => 0));
-        if ($allow_types['category-cat'] || $allow_types['category-cont']) {
-          if ($type != 'category-cat') {
+    case 'node_type_form':
+      $type = $form['old_type']['#value'];
+      if ($type != 'category_cont') {
+        $allow_types = variable_get('category_allow_nodetypes', array('category_cat' => 0, 'category_cont' => 0));
+        if ($allow_types['category_cat'] || $allow_types['category_cont']) {
+          if ($type != 'category_cat') {
             $types_list = array();
-            if ($allow_types['category-cat']) {
-              $types_list['category-cat'] = t('Category');
+            if ($allow_types['category_cat']) {
+              $types_list['category_cat'] = t('Category');
             }
-            if ($allow_types['category-cont']) {
-              $types_list['category-cont'] = t('Container');
+            if ($allow_types['category_cont']) {
+              $types_list['category_cont'] = t('Container');
             }
             $types_list['none'] = t('None');
-            $form['workflow']['category_nodeapi_'. $type] = array(
+            $form['workflow']['category_nodeapi'] = array(
               '#type' => 'radios',
               '#title' => t('Category behavior'),
               '#default_value' => variable_get('category_nodeapi_'. $type, 'none'),
@@ -1025,13 +1041,13 @@ function category_form_alter($form_id, &
               '#description' => t('Adds category or container behaviour to this content type. Setting this to a value other than \'none\' will add additional settings to any content of this type that you create or edit.')
             );
           }
-          if ($allow_types['category-cat']) {
+          if ($allow_types['category_cat']) {
             $containers = array();
             foreach (category_get_containers() as $key => $value) {
               $containers[$key] = $value->admin_title;
             }
-            $default_containers = variable_get('category_nodeapi_'. $type .'_containers', array(0 => 'all'));
-            $form['workflow']['category_nodeapi_'. $type .'_containers'] = array(
+            $default_containers = variable_get('category_nodeapi_containers_'. $type, array(0 => 'all'));
+            $form['workflow']['category_nodeapi_containers'] = array(
               '#type' => 'select',
               '#title' => t('Category - allowed containers'),
               '#default_value' => $default_containers,
@@ -1046,11 +1062,14 @@ function category_form_alter($form_id, &
     // node edit form
     case $type .'_node_form':
       $cat_type = variable_get('category_nodeapi_'. $type, 'none');
+      if ($type == 'category_cat' || $type == 'category_cont') {
+        $cat_type = $type;
+      }
       if ($cat_type != 'none') {
-        $form += category_get_form(($cat_type == 'category-cat'), $node, FALSE);
+        $form += category_get_form(($cat_type == 'category_cat'), $node, FALSE);
       }
 
-      $activeselect = module_exist('activeselect');
+      $activeselect = module_exists('activeselect');
 
       $cats = $node->category;
       if (!isset($cats)) {
@@ -1058,11 +1077,15 @@ function category_form_alter($form_id, &
       }
 
       $default_cat = NULL;
-      if (strpos($_GET['q'], 'node/add') !== FALSE && is_numeric(arg(3))) {
-        $default_cat = arg(3);
+      if (strpos($_GET['q'], 'node/add') !== FALSE && is_numeric(arg(4))) {
+        $default_cat = arg(4);
+
+        if ($cat_type != 'none') {
+          $form['catinfo']['parents']['#default_value'] = array($default_cat => $default_cat);
+        }
       }
 
-      $c = db_query(db_rewrite_sql("SELECT cn.*, n.title FROM {category_cont} cn INNER JOIN {category_cont_node_types} cnt ON cn.cid = cnt.cid INNER JOIN {category} c ON cn.cid = c.cid INNER JOIN {node} n ON cn.cid = n.nid WHERE cnt.type = '%s' AND n.status = 1 AND n.moderate = 0 ORDER BY c.weight, n.title", 'cn', 'cid'), $node->type);
+      $c = db_query(db_rewrite_sql("SELECT cn.*, n.title FROM {category_cont} cn INNER JOIN {category_cont_node_types} cnt ON cn.cid = cnt.cid INNER JOIN {category} c ON cn.cid = c.cid INNER JOIN {node} n ON cn.cid = n.nid WHERE cnt.type = '%s' AND n.status = 1 ORDER BY c.weight, n.title", 'cn', 'cid'), $node->type);
 
       if (db_num_rows($c) > 0) {
         $form['category'] = array(
@@ -1176,7 +1199,7 @@ function category_node_validate(&$node) 
       foreach ($cats['tags'] as $cnid => $cnid_value) {
         $container = category_get_container($cnid);
         if (!$container->tags) {
-          form_set_error("category[tags][$cnid", t('The %name container can not be modified in this way.', array('%name' => theme('placeholder', $container->name))));
+          form_set_error("category[tags][$cnid", t('The %name container can not be modified in this way.', array('%name' => $container->name)));
         }
       }
     }
@@ -1187,24 +1210,13 @@ function category_node_validate(&$node) 
  * Menu callback; displays all nodes associated with a category.
  */
 function category_category_page($str_cids = '', $depth = 0, $op = 'page') {
-  if (preg_match('/^([0-9]+[+ ])+[0-9]+$/', $str_cids)) {
-    $operator = 'or';
-    // The '+' character in a query string may be parsed as ' '.
-    $cids = preg_split('/[+ ]/', $str_cids);
-  }
-  else if (preg_match('/^([0-9]+,)*[0-9]+$/', $str_cids)) {
-    $operator = 'and';
-    $cids = explode(',', $str_cids);
-  }
-  else {
+  $categories = category_categories_parse_string($str_cids);
+  if ($categories['operator'] != 'and' && $categories['operator'] != 'or') {
     drupal_not_found();
   }
 
-  // Needed for '+' to show up in RSS discovery URLs
-  $rss_cids = urlencode($str_cids);
-
-  if ($cids) {
-    $result = db_query(db_rewrite_sql('SELECT c.cid, n.title FROM {category} c INNER JOIN {node} n ON c.cid = n.nid WHERE c.cid IN (%s) AND n.status = 1 AND n.moderate = 0', 'n', 'nid'), implode(',', $cids));
+  if ($categories['cids']) {
+    $result = db_query(db_rewrite_sql('SELECT c.cid, n.title FROM {category} c INNER JOIN {node} n ON c.cid = n.nid WHERE c.cid IN (%s) AND n.status = 1', 'n', 'nid'), implode(',', $categories['cids']));
     $cids = array(); // we rebuild the $cids-array so it only contains categories the user has access to.
     $names = array();
     while ($cat = db_fetch_object($result)) {
@@ -1218,13 +1230,9 @@ function category_category_page($str_cid
 
       switch ($op) {
         case 'page':
-          drupal_add_link(array('rel' => 'alternate',
-                                'type' => 'application/rss+xml',
-                                'title' => 'RSS - '. $title,
-                                'href' => url('category/'. $rss_cids .'/'. $depth .'/feed')));
-
-          $output = category_render_nodes(category_select_nodes($cids, $operator, $depth, TRUE, TRUE));
-          $output .= theme('feed_icon', url("category/$rss_cids/$depth/feed"));
+          $output = category_render_nodes(category_select_nodes($cids, $categories['operator'], $depth, TRUE, TRUE));
+          $output .= theme('feed_icon', url());
+          drupal_add_feed("category/$rss_cids/$depth/feed", 'RSS - '. $title);
           return $output;
           break;
 
@@ -1234,7 +1242,7 @@ function category_category_page($str_cid
           $channel['title'] = variable_get('site_name', 'drupal') .' - '. $title;
           $channel['description'] = $cat->description;
 
-          $result = category_select_nodes($cids, $operator, $depth, FALSE, TRUE);
+          $result = category_select_nodes($cids, $categories['operator'], $depth, FALSE, TRUE);
           node_feed($result, $channel);
           break;
         default:
@@ -1282,7 +1290,7 @@ function category_rss_item($node) {
   $output = array();
   foreach ($node->category as $cat) {
     $is_included = TRUE;
-    if (module_exist('category_display')) {
+    if (module_exists('category_display')) {
       $cont = category_display_cont_load($cat->cnid);
       if (!$cont->nodelinks) {
         $is_included = FALSE;
@@ -1325,7 +1333,7 @@ function category_autocomplete($cnid, $s
   // Fetch last tag
   $last_string = trim(array_pop($array));
   if ($last_string != '') {
-    $result = db_query_range(db_rewrite_sql("SELECT n.title FROM {category} c INNER JOIN {node} n ON c.cid = n.nid WHERE c.cnid = %d AND LOWER(n.title) LIKE LOWER('%%%s%%') AND n.status = 1 AND n.moderate = 0"), $cnid, $last_string, 0, 10);
+    $result = db_query_range(db_rewrite_sql("SELECT n.title FROM {category} c INNER JOIN {node} n ON c.cid = n.nid WHERE c.cnid = %d AND LOWER(n.title) LIKE LOWER('%%%s%%') AND n.status = 1"), $cnid, $last_string, 0, 10);
 
     $prefix = count($array) ? implode(', ', $array) .', ' : '';
 
@@ -1391,6 +1399,10 @@ function category_activeselect($source, 
       $options = _category_category_select_options($cnid, $multiple, '<'. t('root') .'>', $parents, $exclude);
       foreach ($options as $key => $value) {
         unset($options[$key]);
+        $value = $value->option;
+        end($value);
+        $key = key($value);
+        $value = array_pop($value);
         $options[$key]['value'] = $value;
         $options[$key]['selected'] = in_array($key, $parents);
       }
@@ -1503,8 +1515,10 @@ function category_activeselect($source, 
  * @param $op
  *   The operation being performed ('install' or 'uninstall').
  */
-function category_wrapper($type = NULL, $op = NULL) {
-  $goto = 'admin/settings/category';
+function category_wrapper($type = NULL, $op = NULL, $goto = NULL, $rebuild = TRUE) {
+  if (!isset($goto)) {
+    $goto = 'admin/content/category/settings';
+  }
   $generic_error = ' '. t('Unable to perform the specified operation.');
 
   // Various validation checks
@@ -1512,13 +1526,13 @@ function category_wrapper($type = NULL, 
     drupal_set_message(t('Invalid parameters supplied to wrapper install / uninstall script.'). $generic_error, 'error');
     drupal_goto($goto);
   }
-  if (!module_exist($type)) {
+  if (!module_exists($type)) {
     drupal_set_message(t('The %type module is not currently enabled. You must enable it before performing an install or uninstall.', array('%type' => $type)), 'error');
     drupal_goto($goto);
   }
   $status = category_get_wrapper_status($type);
   if (($status && $op == 'install') || (!$status && $op == 'uninstall')) {
-    drupal_set_message(t('The %type module is already %status.', array('%type' => $type, '%status' => ($status ? t('installed') : t('uninstalled')))). $generic_error, 'error');
+    drupal_set_message(t('The %type module is already @status.', array('%type' => $type, '@status' => ($status ? t('installed') : t('uninstalled')))). $generic_error, 'error');
     drupal_goto($goto);
   }
 
@@ -1529,6 +1543,12 @@ function category_wrapper($type = NULL, 
     drupal_set_message(t('The file %filename could not be found.', array('%filename' => $module_file)). $generic_error, 'error');
     drupal_goto($goto);
   }
+  $info_file = $type .'.info';
+  $info_file_path = $module_path .'/'. $info_file;
+  if (!file_exists($info_file_path)) {
+    drupal_set_message(t('The file %filename could not be found.', array('%filename' => $info_file)). $generic_error, 'error');
+    drupal_goto($goto);
+  }
   if ($op == 'install') {
     $wrapper_file = $type. '.module.copyme';
     $wrapper_file_path = drupal_get_path('module', 'category'). '/wrappers/'. $wrapper_file;
@@ -1536,6 +1556,12 @@ function category_wrapper($type = NULL, 
       drupal_set_message(t('The file %filename could not be found.', array('%filename' => $wrapper_file)). $generic_error, 'error');
       drupal_goto($goto);
     }
+    $wrapper_info_file = $type. '.info.copyme';
+    $wrapper_info_file_path = drupal_get_path('module', 'category'). '/wrappers/'. $wrapper_info_file;
+    if (!file_exists($wrapper_info_file_path)) {
+      drupal_set_message(t('The file %filename could not be found.', array('%filename' => $wrapper_info_file)). $generic_error, 'error');
+      drupal_goto($goto);
+    }
     if (!@copy($wrapper_file_path, $module_path. '/'. $wrapper_file)) {
       drupal_set_message(t('The file %filename could not be copied.', array('%filename' => $wrapper_file)). $generic_error, 'error');
       drupal_goto($goto);
@@ -1549,6 +1575,19 @@ function category_wrapper($type = NULL, 
       drupal_set_message(t('The file %filename could not be renamed.', array('%filename' => $wrapper_file)). $generic_error, 'error');
       drupal_goto($goto);
     }
+    if (!@copy($wrapper_info_file_path, $module_path. '/'. $wrapper_info_file)) {
+      drupal_set_message(t('The file %filename could not be copied.', array('%filename' => $wrapper_info_file)). $generic_error, 'error');
+      drupal_goto($goto);
+    }
+    if (!@rename($info_file_path, $info_file_path. '.old')) {
+      drupal_set_message(t('The file %filename could not be renamed.', array('%filename' => $info_file)). $generic_error, 'error');
+      drupal_goto($goto);
+    }
+    $wrapper_info_new_path = $module_path. '/'. $wrapper_info_file;
+    if (!@rename($wrapper_info_new_path, $info_file_path)) {
+      drupal_set_message(t('The file %filename could not be renamed.', array('%filename' => $wrapper_info_file)). $generic_error, 'error');
+      drupal_goto($goto);
+    }
   }
   else {
     $old_file = $type. '.module.old';
@@ -1557,6 +1596,12 @@ function category_wrapper($type = NULL, 
       drupal_set_message(t('The file %filename could not be found.', array('%filename' => $old_file)). $generic_error, 'error');
       drupal_goto($goto);
     }
+    $old_info_file = $type. '.info.old';
+    $old_info_file_path = drupal_get_path('module', $type). '/'. $old_info_file;
+    if (!file_exists($old_info_file_path)) {
+      drupal_set_message(t('The file %filename could not be found.', array('%filename' => $old_info_file)). $generic_error, 'error');
+      drupal_goto($goto);
+    }
     if (!@unlink($module_file_path)) {
       drupal_set_message(t('The file %filename could not be deleted.', array('%filename' => $module_file)). $generic_error, 'error');
       drupal_goto($goto);
@@ -1565,12 +1610,23 @@ function category_wrapper($type = NULL, 
       drupal_set_message(t('The file %filename could not be renamed.', array('%filename' => $old_file)). $generic_error, 'error');
       drupal_goto($goto);
     }
+    if (!@unlink($info_file_path)) {
+      drupal_set_message(t('The file %filename could not be deleted.', array('%filename' => $info_file)). $generic_error, 'error');
+      drupal_goto($goto);
+    }
+    if (!@rename($old_info_file_path, $info_file_path)) {
+      drupal_set_message(t('The file %filename could not be renamed.', array('%filename' => $old_info_file)). $generic_error, 'error');
+      drupal_goto($goto);
+    }
   }
 
-  drupal_set_message(t('The %type wrapper was %op successfully.', array('%type' => $type, '%op' => ($op == 'install' ? t('installed') : t('uninstalled')))));
-  module_list(TRUE, FALSE);
-  menu_rebuild();
-  drupal_goto($goto);
+  drupal_set_message(t('The @type wrapper was @op successfully.', array('@type' => $type, '@op' => ($op == 'install' ? t('installed') : t('uninstalled')))));
+
+  if ($rebuild) {
+    module_list(TRUE, FALSE);
+    menu_rebuild();
+    drupal_goto($goto);
+  }
 }
 
 function theme_category_view($node) {
@@ -1579,13 +1635,13 @@ function theme_category_view($node) {
   $show_nodes = FALSE;
 
   if (db_num_rows($nodes) > 0) {
-    if (!module_exist('category_display') || $node->show_listing) {
+    if (!module_exists('category_display') || $node->show_listing) {
       $show_nodes = TRUE;
     }
   }
   else {
-    if (!module_exist('category_display')) {
-      if ($type == 'category-cont') {
+    if (!module_exists('category_display')) {
+      if ($type == 'category_cont') {
         if ($node->depth) {
           $show_nodes = TRUE;
         }
@@ -1596,7 +1652,7 @@ function theme_category_view($node) {
     }
     else {
       if ($node->show_listing) {
-        if ($type == 'category-cont') {
+        if ($type == 'category_cont') {
           if ($node->depth && $node->emptymsg) {
             $show_nodes = TRUE;
           }
@@ -1613,33 +1669,32 @@ function theme_category_view($node) {
   // Allow other modules to add additional output.
   $extra = module_invoke_all('category', 'view', $node);
   if (isset($extra) && is_array($extra)) {
-    foreach ($extra as $key => $value) {
-      $node->body .= $value;
-    }
+    $node->content += $extra;
   }
 
   if ($show_nodes) {
-    drupal_add_link(array('rel' => 'alternate',
-                                   'type' => 'application/rss+xml',
-                                   'title' => 'RSS - '. $node->title,
-                                   'href' => url('node/'. $node->nid .'/feed')));
+    drupal_add_feed('node/'. $node->nid .'/feed', 'RSS - '. $node->title);
 
     $use_views = FALSE;
-    if (module_exist('category_views')) {
+    if (module_exists('category_views')) {
       $use_views = category_views_is_visible($node, $type);
     }
 
     if ($use_views) {
-      $node->body .= category_views_render_nodes($node);
+      $node->content['category_listing'] = array(
+        '#value' => category_views_render_nodes($node),
+        '#weight' => 10
+      );
     }
     else {
-      $node->body .= category_render_nodes($nodes);
+      $node->content['category_listing'] = array(
+        '#value' => category_render_nodes($nodes),
+        '#weight' => 10
+      );
     }
-
-    $node->body .= theme('feed_icon', url("node/$node->nid/feed"));
   }
 
-  return $node->body;
+  return $node->content;
 }
 
 /**
@@ -1654,22 +1709,23 @@ function theme_category_view($node) {
  *   Themed output.
  */
 function theme_category_wrapper_status($type, $status) {
-  theme_add_style(drupal_get_path('module', 'category'). '/category.css');
-  $output = '';
+  drupal_add_css(drupal_get_path('module', 'category'). '/category.css');
+  $output = '<p>';
 
-  if (module_exist($type)) {
-    $status_string = $status ? ('<span class="category-wrapper-installed">'. t('installed'). '</span>') : ('<span class="category-wrapper-notinstalled">'. t('not installed'). '</span>');
-    $output .= '<p>'. t('The %type wrapper is currently %status-string.', array('%type' => $type, '%status-string' => $status_string)). "\n";
-
-    $install_string = $status ? t('Uninstall now') : t('Install now');
-    $op = $status ? 'uninstall' : 'install';
-    $output .= '<br/>'. (l($install_string, t('category/wrapper/%type/%op', array('%type' => $type, '%op' => $op)))). ".</p>\n";
+  if (module_exists($type)) {
+    if ($status) {
+      $output .= t('The @type wrapper is currently <span class="category-wrapper-installed">installed</span>.', array('@type' => $type)). "\n";
+      $output .= '<br/>'. l(t('Uninstall now'), "category/wrapper/$type/uninstall");
+    }
+    else {
+      $output .= '<p>'. t('The @type wrapper is currently <span class="category-wrapper-notinstalled">not installed</span>.', array('@type' => $type)). "\n";
+      $output .= '<br/>'. l(t('Install now'), "category/wrapper/$type/install");
+    }
   }
   else {
-    $status_string = '<span class="category-wrapper-notinstalled">'. t('not enabled'). '</span>';
-    $output .= '<p>'. t('The %type module (original or wrapper) is currently %status-string. You must enable it on the %module-admin-page before you can perform an install or an uninstall.', array('%type' => $type, '%status-string' => $status_string, '%module-admin-page' => l(t('module administration page'), 'admin/modules'))). "</p>\n";
+    $output .= t('The !type module (original or wrapper) is currently <span class="category-wrapper-notinstalled">not enabled</span>. You must enable it on the <a href="!module-admin-page">module administration page</a> before you can perform an install or an uninstall.', array('!type' => $type, '!module-admin-page' => url('admin/modules'))). "\n";
   }
-
+  $output .= '</p>';
   return $output;
 }
 
@@ -1810,7 +1866,9 @@ function _category_category_select_optio
     foreach ($tree as $category) {
       // Boolean blasphemy has been cleaned up and moved to separate function
       if (_category_category_select_check_category($category, $container, $cnid, $exclude)) {
-        $options[$category->cid] = _category_depth($category->depth, '-') . ($category->cnid ? $category->title : $category->admin_title) . ($category->cnid ? '' : ' *');
+        $choice = new stdClass();
+        $choice->option = array($category->cid => str_repeat('-', $category->depth) . ($category->cnid ? $category->title : $category->admin_title) . ($category->cnid ? '' : ' *'));
+        $options[] = $choice;
       }
     }
     if (!$blank && !$value && !$multiple && !$default_set) {
@@ -1913,7 +1971,7 @@ function _category_node_select_options($
   if ($tree) {
     foreach ($tree as $category) {
       if (!in_array($category->cid, $exclude) && node_access('view', node_load($category->cid))) {
-        $options[$category->cid] = _category_depth($category->depth, '-') . $category->title;
+        $options[$category->cid] = str_repeat('-', $category->depth) . $category->title;
       }
     }
     if (!$blank && !$value) {
@@ -1942,7 +2000,7 @@ function _category_node_select_options($
  *   specified node type.
  */
 function _category_type_allowed_container($type, $cnid) {
-  $cont_list = variable_get('category_nodeapi_'. $type .'_containers', array(0 => 'all'));
+  $cont_list = variable_get('category_nodeapi_containers_'. $type, array(0 => 'all'));
 
   if (empty($cont_list) || !is_array($cont_list)) {
     return TRUE;
Index: category_display/category_display.info
===================================================================
RCS file: category_display/category_display.info
diff -N category_display/category_display.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ category_display/category_display.info	5 Jan 2007 15:20:49 -0000
@@ -0,0 +1,5 @@
+; $Id$
+name = Category display
+description = Allows additional output to be displayed and toggled for category and container nodes.
+package = Category
+dependencies = category
Index: category_display/category_display.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/category/category_display/category_display.module,v
retrieving revision 1.32
diff -u -p -r1.32 category_display.module
--- category_display/category_display.module	13 Nov 2006 13:19:37 -0000	1.32
+++ category_display/category_display.module	5 Jan 2007 15:20:50 -0000
@@ -12,8 +12,6 @@
  */
 function category_display_help($section) {
   switch ($section) {
-    case 'admin/modules#description':
-      return t('Allows additional output to be displayed and toggled for category and container nodes. Requires the category module.');
     case 'admin/help#category_display':
       return t('<p>The category display module allows additional output to be displayed and toggled for category and container nodes.</p><p>This module requires the category module.</p>');
   }
@@ -27,7 +25,7 @@ function category_display_nodeapi(&$node
     case 'load':
       if (category_is_cat_or_cont($node->nid)) {
         $type = category_node_get_type($node);
-        $is_cat = $type == 'category-cat';
+        $is_cat = $type == 'category_cat';
         if (!$is_cat) {
           return (array)category_display_cont_load($node->nid, $node);
         }
@@ -57,7 +55,7 @@ function category_display_nodeapi(&$node
       }
       elseif (category_is_cat_or_cont($node->nid, TRUE)) {
         $type = category_node_get_type($node);
-        $is_cat = $type == 'category-cat';
+        $is_cat = $type == 'category_cat';
         if (!$is_cat) {
           category_display_cont_update($node);
         }
@@ -66,7 +64,7 @@ function category_display_nodeapi(&$node
     case 'delete':
       if (category_is_cat_or_cont($node->nid)) {
         $type = category_node_get_type($node);
-        $is_cat = $type == 'category-cat';
+        $is_cat = $type == 'category_cat';
         if (!$is_cat) {
           category_display_cont_delete($node->nid);
         }
@@ -159,7 +157,12 @@ function category_display_category($op, 
       return $form;
       break;
     case 'view':
-      return theme('category_display_navigation', $node);
+      return array(
+        'category_display_navigation' => array(
+          '#value' => theme('category_display_navigation', $node),
+          '#weight' => 5
+        )
+      );
   }
 }
 
@@ -333,7 +336,7 @@ function theme_category_display_navigati
     $navlinks = FALSE;
 
     $type = category_node_get_type($node);
-    $is_cat = $type == 'category-cat';
+    $is_cat = $type == 'category_cat';
     if ($node->toc_for_cats && ($is_cat || !$node->hidden_cont)) {
       $show_toc = TRUE;
     }
@@ -378,13 +381,13 @@ function theme_category_display_navigati
       }
 
       if (isset($toc) || isset($links)) {
-        theme_add_style(drupal_get_path('module', 'category_display'). '/category_display.css');
+        drupal_add_css(drupal_get_path('module', 'category_display'). '/category_display.css');
         $output .= '<div class="category-navigation">';
         if (isset($toc)) {
           $output .= $toc;
         }
         if (isset($links)) {
-          $output .= '<div class="page-links">'. $links .'</div>';
+          $output .= '<div class="page-links clear-block">'. $links .'</div>';
         }
         $output .= '</div>';
       }
@@ -421,7 +424,7 @@ function _category_display_navlinks($nid
   if ($nid) {
     $node = node_load($nid);
     $type = category_node_get_type($node);
-    $is_cat = $type == 'category-cat';
+    $is_cat = $type == 'category_cat';
     if ($node->navlinks) {
       if ($is_cat || !$node->hidden_cont) {
         $dist_check = FALSE;
Index: category_export/category_export.info
===================================================================
RCS file: category_export/category_export.info
diff -N category_export/category_export.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ category_export/category_export.info	5 Jan 2007 15:20:50 -0000
@@ -0,0 +1,5 @@
+; $Id$
+name = Category export
+description = Allows category trees to be exported as printer-friendly HTML.
+package = Category
+dependencies = category
Index: category_export/category_export.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/category/category_export/category_export.module,v
retrieving revision 1.9
diff -u -p -r1.9 category_export.module
--- category_export/category_export.module	13 May 2006 14:28:36 -0000	1.9
+++ category_export/category_export.module	5 Jan 2007 15:20:50 -0000
@@ -11,9 +11,7 @@
  */
 function category_export_help($section) {
   switch ($section) {
-    case 'admin/modules#description':
-      return t('Allows category trees to be exported as printer-friendly HTML. Requires the category module.');
-    case 'admin/help#category_menu':
+    case 'admin/help#category_export':
       return t('<p>The category export module allows category trees to be exported as printer-friendly HTML. Users with the \'view printer-friendly categories\' permission will see a \'view printer-friendly version\' link on category pages, which they can click to access the printer-friendly HTML. This module requires the category module.</p>');
   }
 }
@@ -26,7 +24,7 @@ function category_export_nodeapi(&$node,
     case 'load':
       if (category_is_cat_or_cont($node->nid)) {
         $type = category_node_get_type($node);
-        $is_cat = $type == 'category-cat';
+        $is_cat = $type == 'category_cat';
         if (!$is_cat) {
           return (array)category_export_cont_load($node->nid);
         }
@@ -56,7 +54,7 @@ function category_export_nodeapi(&$node,
       }
       elseif (category_is_cat_or_cont($node->nid, TRUE)) {
         $type = category_node_get_type($node);
-        $is_cat = $type == 'category-cat';
+        $is_cat = $type == 'category_cat';
         if (!$is_cat) {
           category_export_cont_update($node);
         }
@@ -64,7 +62,7 @@ function category_export_nodeapi(&$node,
       break;
     case 'delete':
       $type = category_node_get_type($node);
-      $is_cat = $type == 'category-cat';
+      $is_cat = $type == 'category_cat';
       if (!$is_cat) {
         category_export_cont_delete($node->nid);
       }
@@ -195,9 +193,11 @@ function category_export_link($type, $no
   if ($type == 'node' && isset($node->parents)) {
     if (!$main && isset($node->export_types) && in_array('html', $node->export_types)) {
       if (user_access('see printer-friendly categories')) {
-        $links[] = l(t('printer-friendly version'),
-                     'category/export/html/'. $node->nid,
-                     array('title' => t('Show a printer-friendly version of this category and its sub-pages.')));
+        $links['category_export_html'] = array(
+          'title' => t('printer-friendly version'),
+          'href' => 'category/export/html/'. $node->nid,
+          'attributes' => array('title' => t('Show a printer-friendly version of this category and its sub-pages.'))
+        );
       }
     }
   }
Index: category_legacy/category_legacy.info
===================================================================
RCS file: category_legacy/category_legacy.info
diff -N category_legacy/category_legacy.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ category_legacy/category_legacy.info	5 Jan 2007 15:20:50 -0000
@@ -0,0 +1,5 @@
+; $Id$
+name = Category legacy
+description = Allows you to convert your taxonomy and book data into category data, and vice versa.
+package = Category
+dependencies = category
Index: category_legacy/category_legacy.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/category/category_legacy/category_legacy.module,v
retrieving revision 1.27
diff -u -p -r1.27 category_legacy.module
--- category_legacy/category_legacy.module	17 Sep 2006 14:57:02 -0000	1.27
+++ category_legacy/category_legacy.module	5 Jan 2007 15:20:52 -0000
@@ -12,25 +12,23 @@
  */
 function category_legacy_help($section) {
   switch ($section) {
-    case 'admin/modules#description':
-      return t('Allows you to convert your taxonomy and book data into category data, and vice versa. Requires the category module.');
-    case 'admin/help#category_menu':
+    case 'admin/help#category_legacy':
       return t('<p>The category legacy module lets you import vocabularies and terms from the taxonomy module, and books from the book module. These are then converted into containers and categories. You can also export containers and categories back to the taxonomy and book modules. It is strongly recommended that you back up all existing taxonomy and book data on your site, before performing any operations using this module.</p><p>This module requires the category module.</p>');
     case 'admin/category/legacy':
       $output = '<p>'. t('Select the vocabularies that you wish to import. Only vocabularies that do not already have equivalent containers are listed. A vocabulary is defined as legacy (and therefore appears on this list) only if no container can be found with the same ID, and with the same title.'). '</p>';
       $output .= '<p>'. t('For each vocabulary that you select, the vocabulary and all its terms will be imported into the category system. Vocabularies will become containers, and terms will become categories. Vocabularies and terms have their own vocabulary and term IDs, whereas categories and containers use the more standard node IDs; therefore, in order to avoid any possible conflict in sequencing, everything that you import will be given a new node ID, and will lose its old vocabulary or term ID.'). '</p>';
       $output .= '<p>'. t('<strong>Warning:</strong> all vocabularies and terms that you import will be deleted from the taxonomy database tables! If you have the taxonomy wrapper installed, then they will all be re-inserted, and will be untouched except for having new IDs, to match your newly imported categories and containers. If you have any doubts, you should enable the \'backup all selected data\' option before proceeding.'). '</p>';
       return $output;
-    case 'admin/category/legacy/import/book':
+    case 'admin/content/category/legacy/import/book':
       $output = '<p>'. t('Select the books that you wish to import. Only books that do not already have equivalent containers are listed. A book is defined as legacy (and therefore appears on this list) only if no container can be found with the same ID, and with the same title.'). '</p>';
       $output .= '<p>'. t('For each book that you select, the book and all its children will be imported into the category system. Root book pages will become containers, and all child pages will become categories. The node IDs for each book page will be preserved during the import, and will remain unchanged once the book pages are transformed into categories and containers.'). '</p>';
       return $output;
-    case 'admin/category/legacy/export':
+    case 'admin/content/category/legacy/export':
       $output = '<p>'. t('Select the containers that you wish to export. Only containers that do not already have equivalent vocabularies are listed. A container is defined as legacy (and therefore appears on this list) only if no vocabulary can be found with the same ID, and with the same title.'). '</p>';
       $output .= '<p>'. t('For each container that you select, the container and all its categories will be exported to the taxonomy system. Containers will become vocabularies, and categories will become terms. Vocabularies and terms have their own vocabulary and term IDs, whereas categories and containers use the more standard node IDs; therefore, in order to avoid any possible conflict in sequencing, everything that you export will be given a new vocabulary or term ID, and will lose its old node ID.'). '</p>';
       $output .= '<p>'. t('<strong>Warning:</strong> all containers and categories that you export will be deleted from the category database tables! Additionally, because the category system holds more data fields than the taxonomy system, any fields that do not have an equivalent in the taxonomy system will be lost. If you have any doubts, you should enable the \'backup all selected data\' option before proceeding.'). '</p>';
       return $output;
-    case 'admin/category/legacy/export/book':
+    case 'admin/content/category/legacy/export/book':
       $output = '<p>'. t('Select the containers that you wish to export. Only containers that do not already have equivalent books are listed. A container is defined as legacy (and therefore appears on this list) only if no book can be found with the same ID, and with the same title.'). '</p>';
       $output .= '<p>'. t('For each container that you select, the container and all its categories will be exported to the book system. Containers will become root book pages, and all categories will become child pages. The node IDs for each container and category will be preserved during the export, and will remain unchanged once the categories and containers are transformed into book pages.'). '</p>';
       $output .= '<p>'. t('<strong>Warning:</strong> because the category system holds more data fields than the book system, any fields that do not have an equivalent in the book system will be lost. If you have any doubts, you should enable the \'backup all selected data\' option before proceeding.'). '</p>';
@@ -46,48 +44,54 @@ function category_legacy_menu($may_cache
 
   if ($may_cache) {
     $items[] = array(
-      'path' => 'admin/category/legacy',
-      'title' => t('category legacy'),
-      'callback' => 'category_legacy_import',
+      'path' => 'admin/content/category/legacy',
+      'title' => t('Category legacy'),
       'access' => user_access('administer categories'),
+      'callback' => 'drupal_get_form',
+      'callback arguments' => array('category_legacy_import_taxonomy_form'),
     );
     $items[] = array(
-      'path' => 'admin/category/legacy/import',
-      'title' => t('import'),
+      'path' => 'admin/content/category/legacy/import',
+      'title' => t('Import'),
       'access' => user_access('administer categories'),
       'type' => MENU_DEFAULT_LOCAL_TASK,
       'weight' => -10,
     );
     $items[] = array(
-      'path' => 'admin/category/legacy/import/taxonomy',
-      'title' => t('taxonomy'),
+      'path' => 'admin/content/category/legacy/import/taxonomy',
+      'title' => t('Taxonomy'),
       'type' => MENU_DEFAULT_LOCAL_TASK,
       'weight' => -10,
     );
     $items[] = array(
-      'path' => 'admin/category/legacy/import/book',
-      'title' => t('book'),
+      'path' => 'admin/content/category/legacy/import/book',
+      'title' => t('Book'),
+      'callback' => 'drupal_get_form',
+      'callback arguments' => array('category_legacy_import_book_form'),
       'access' => user_access('administer categories'),
       'type' => MENU_LOCAL_TASK,
       'weight' => -6,
     );
     $items[] = array(
-      'path' => 'admin/category/legacy/export',
-      'title' => t('export'),
-      'callback' => 'category_legacy_export',
+      'path' => 'admin/content/category/legacy/export',
+      'title' => t('Export'),
       'access' => user_access('administer categories'),
+      'callback' => 'drupal_get_form',
+      'callback arguments' => array('category_legacy_export_taxonomy_form'),
       'type' => MENU_LOCAL_TASK,
       'weight' => -6,
     );
     $items[] = array(
-      'path' => 'admin/category/legacy/export/taxonomy',
-      'title' => t('taxonomy'),
+      'path' => 'admin/content/category/legacy/export/taxonomy',
+      'title' => t('Taxonomy'),
       'type' => MENU_DEFAULT_LOCAL_TASK,
       'weight' => -10,
     );
     $items[] = array(
-      'path' => 'admin/category/legacy/export/book',
-      'title' => t('book'),
+      'path' => 'admin/content/category/legacy/export/book',
+      'title' => t('Book'),
+      'callback' => 'drupal_get_form',
+      'callback arguments' => array('category_legacy_export_book_form'),
       'access' => user_access('administer categories'),
       'type' => MENU_LOCAL_TASK,
       'weight' => -6,
@@ -97,7 +101,7 @@ function category_legacy_menu($may_cache
     if (category_legacy_get_term_path_status()) {
       $items[] = array(
         'path' => 'taxonomy/term',
-        'title' => t('taxonomy term'),
+        'title' => t('Taxonomy term'),
         'callback' => 'category_legacy_term_page',
         'access' => user_access('access content'),
         'type' => MENU_CALLBACK,
@@ -112,6 +116,29 @@ function category_legacy_menu($may_cache
 }
 
 /**
+ * Implementation of hook_forms().
+ */
+function category_legacy_forms() {
+  $forms['category_legacy_import_book_form'] = array(
+    'callback' => 'category_legacy_import_form_build',
+    'callback arguments' => array('book'),
+  );
+  $forms['category_legacy_import_taxonomy_form'] = array(
+    'callback' => 'category_legacy_import_form_build',
+    'callback arguments' => array('taxonomy'),
+  );
+  $forms['category_legacy_export_book_form'] = array(
+    'callback' => 'category_legacy_export_form_build',
+    'callback arguments' => array('book'),
+  );
+  $forms['category_legacy_export_taxonomy_form'] = array(
+    'callback' => 'category_legacy_export_form_build',
+    'callback arguments' => array('taxonomy'),
+  );
+  return $forms;
+}
+
+/**
  * Implementation of hook_nodeapi().
  */
 function category_legacy_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
@@ -119,7 +146,7 @@ function category_legacy_nodeapi(&$node,
     case 'delete':
       if (category_is_cat_or_cont($node->nid)) {
         $type = category_node_get_type($node);
-        $is_cat = $type == 'category-cat';
+        $is_cat = $type == 'category_cat';
         if ($is_cat) {
           category_legacy_map_delete($node->nid);
         }
@@ -175,7 +202,7 @@ function category_legacy_category_legacy
         }
       }
 
-      if (module_exist('path')) {
+      if (module_exists('path')) {
         if ($edit['change_old_aliases']) {
           $paths = category_legacy_get_path_cache();
           foreach ($paths as $path) {
@@ -213,7 +240,7 @@ function category_legacy_category_legacy
         }
       }
 
-      if (module_exist('path')) {
+      if (module_exists('path')) {
         if ($edit['change_old_aliases']) {
           $paths = category_legacy_get_path_cache();
           foreach ($paths as $path) {
@@ -245,7 +272,7 @@ function category_legacy_category_legacy
 /**
  * Menu callback; displays the screen for importing taxonomy or book data.
  */
-function category_legacy_import($arg1 = 'import', $import_type = 'taxonomy') {
+function category_legacy_import_form_build($import_type, $arg1 = 'import') {
   $form = array();
 
   if ($import_type == 'taxonomy') {
@@ -293,12 +320,12 @@ function category_legacy_import($arg1 = 
       );
 
       $alias_paths = array(
-        '%taxonomy-path' => theme('placeholder', 'taxonomy/term/x'),
-        '%category-path' => theme('placeholder', 'node/y'),
-        '%taxonomy-rss' => theme('placeholder', 'taxonomy/term/x/0/feed'),
-        '%category-rss' => theme('placeholder', 'node/y/feed'),
-        '%taxonomy-query' => theme('placeholder', 'taxonomy/term/x+y'),
-        '%category-query' => theme('placeholder', 'category/x+y'),
+        '%taxonomy-path' => 'taxonomy/term/x',
+        '%category-path' => 'node/y',
+        '%taxonomy-rss' => 'taxonomy/term/x/0/feed',
+        '%category-rss' => 'node/y/feed',
+        '%taxonomy-query' => 'taxonomy/term/x+y',
+        '%category-query' => 'category/x+y',
       );
       $form['category_legacy']['redirect_old_paths'] = array(
         '#type' => 'radios',
@@ -308,7 +335,7 @@ function category_legacy_import($arg1 = 
         '#required' => TRUE,
       );
 
-      if (module_exist('path')) {
+      if (module_exists('path')) {
         $form['category_legacy']['change_old_aliases'] = array(
           '#type' => 'radios',
           '#title' => t('Change existing legacy path aliases'),
@@ -339,7 +366,7 @@ function category_legacy_import($arg1 = 
     );
   }
 
-  return drupal_get_form('category_legacy_import_'. $import_type, $form);
+  return $form;
 }
 
 /**
@@ -352,7 +379,7 @@ function category_legacy_import($arg1 = 
  * @return
  *   A themed form for display.
  */
-function theme_category_legacy_import_taxonomy($form) {
+function theme_category_legacy_import_taxonomy_form($form) {
   $output = '';
   $vocabularies = category_legacy_get_old_vocabularies();
 
@@ -361,7 +388,7 @@ function theme_category_legacy_import_ta
   $rows = array();
 
   while ($data = db_fetch_object($result)) {
-    $rows[] = array(array('data' => form_render($form['vocabulary'][$data->vid]), 'align' => 'center'), $data->name, array('data' => $data->vid, 'align' => 'center'), array('data' => $data->tid_count, 'align' => 'center'));
+    $rows[] = array(drupal_render($form['vocabulary'][$data->vid]), $data->name, array('data' => $data->vid, 'align' => 'center'), array('data' => $data->tid_count, 'align' => 'center'));
   }
 
   if (empty($rows)) {
@@ -372,7 +399,7 @@ function theme_category_legacy_import_ta
   $output .= theme('pager', NULL, 50, 0);
 
   if (!empty($vocabularies)) {
-    $output .= form_render($form);
+    $output .= drupal_render($form);
   }
 
   return $output;
@@ -388,7 +415,7 @@ function theme_category_legacy_import_ta
  * @return
  *   A themed form for display.
  */
-function theme_category_legacy_import_book($form) {
+function theme_category_legacy_import_book_form($form) {
   $output = '';
   $books = category_legacy_get_old_books();
 
@@ -397,7 +424,7 @@ function theme_category_legacy_import_bo
   $rows = array();
 
   while ($data = db_fetch_object($result)) {
-    $rows[] = array(array('data' => form_render($form['books'][$data->nid]), 'align' => 'center'), $data->title, array('data' => $data->nid, 'align' => 'center'), array('data' => $data->child_count, 'align' => 'center'));
+    $rows[] = array(array('data' => drupal_render($form['books'][$data->nid]), 'align' => 'center'), $data->title, array('data' => $data->nid, 'align' => 'center'), array('data' => $data->child_count, 'align' => 'center'));
   }
 
   if (empty($rows)) {
@@ -408,13 +435,13 @@ function theme_category_legacy_import_bo
   $output .= theme('pager', NULL, 50, 0);
 
   if (!empty($books)) {
-    $output .= form_render($form);
+    $output .= drupal_render($form);
   }
 
   return $output;
 }
 
-function category_legacy_import_taxonomy_validate($form_id, $form_values) {
+function category_legacy_import_taxonomy_form_validate($form_id, $form_values) {
   $vocabs_selected = FALSE;
 
   if (isset($form_values['vocabulary']) && is_array($form_values['vocabulary'])) {
@@ -431,7 +458,7 @@ function category_legacy_import_taxonomy
   }
 }
 
-function category_legacy_import_book_validate($form_id, $form_values) {
+function category_legacy_import_book_form_validate($form_id, $form_values) {
   $books_selected = FALSE;
 
   if (isset($form_values['books']) && is_array($form_values['books'])) {
@@ -452,7 +479,7 @@ function category_legacy_import_book_val
  * Control function for all actions that occur after the user submits the
  * taxonomy import form.
  */
-function category_legacy_import_taxonomy_submit($form_id, $form_values) {
+function category_legacy_import_taxonomy_form_submit($form_id, $form_values) {
   $vocabularies = array();
   $legacy_map = array();
 
@@ -529,7 +556,7 @@ function category_legacy_import_taxonomy
  * Control function for all actions that occur after the user submits the
  * book import form.
  */
-function category_legacy_import_book_submit($form_id, $form_values) {
+function category_legacy_import_book_form_submit($form_id, $form_values) {
   $books = array();
 
   // Build all book data in one big nested array
@@ -573,7 +600,7 @@ function category_legacy_import_book_sub
 /**
  * Menu callback; displays the screen for exporting category data to taxonomy or book.
  */
-function category_legacy_export($export_type = 'taxonomy') {
+function category_legacy_export_form_build($export_type) {
   $form = array();
 
   $categories = category_legacy_get_old_containers($export_type);
@@ -608,14 +635,14 @@ function category_legacy_export($export_
         '#required' => TRUE,
       );
 
-      if (module_exist('path')) {
+      if (module_exists('path')) {
         $alias_paths = array(
-          '%taxonomy-path' => theme('placeholder', 'taxonomy/term/x'),
-          '%category-path' => theme('placeholder', 'node/y'),
-          '%taxonomy-rss' => theme('placeholder', 'taxonomy/term/x/0/feed'),
-          '%category-rss' => theme('placeholder', 'node/y/feed'),
-          '%taxonomy-query' => theme('placeholder', 'taxonomy/term/x+y'),
-          '%category-query' => theme('placeholder', 'category/x+y'),
+          '%taxonomy-path' => 'taxonomy/term/x',
+          '%category-path' => 'node/y',
+          '%taxonomy-rss' => 'taxonomy/term/x/0/feed',
+          '%category-rss' => 'node/y/feed',
+          '%taxonomy-query' => 'taxonomy/term/x+y',
+          '%category-query' => 'category/x+y',
         );
         $form['category_legacy']['redirect_old_paths'] = array(
           '#type' => 'radios',
@@ -659,7 +686,7 @@ function category_legacy_export($export_
     );
   }
 
-  return drupal_get_form('category_legacy_export_'. $export_type, $form);
+  return $form;
 }
 
 /**
@@ -672,7 +699,7 @@ function category_legacy_export($export_
  * @return
  *   A themed form for display.
  */
-function theme_category_legacy_export_taxonomy($form) {
+function theme_category_legacy_export_taxonomy_form($form) {
   $output = '';
   $containers = category_legacy_get_old_containers('taxonomy');
 
@@ -681,7 +708,7 @@ function theme_category_legacy_export_ta
   $rows = array();
 
   while ($data = db_fetch_object($result)) {
-    $rows[] = array(array('data' => form_render($form['categories'][$data->nid]), 'align' => 'center'), $data->title, array('data' => $data->nid, 'align' => 'center'), array('data' => $data->cid_count, 'align' => 'center'));
+    $rows[] = array(array('data' => drupal_render($form['categories'][$data->nid]), 'align' => 'center'), $data->title, array('data' => $data->nid, 'align' => 'center'), array('data' => $data->cid_count, 'align' => 'center'));
   }
 
   if (empty($rows)) {
@@ -692,7 +719,7 @@ function theme_category_legacy_export_ta
   $output .= theme('pager', NULL, 50, 0);
 
   if (!empty($containers)) {
-    $output .= form_render($form);
+    $output .= drupal_render($form);
   }
 
   return $output;
@@ -708,7 +735,7 @@ function theme_category_legacy_export_ta
  * @return
  *   A themed form for display.
  */
-function theme_category_legacy_export_book($form) {
+function theme_category_legacy_export_book_form($form) {
   $output = '';
   $containers = category_legacy_get_old_containers('book');
 
@@ -717,7 +744,7 @@ function theme_category_legacy_export_bo
   $rows = array();
 
   while ($data = db_fetch_object($result)) {
-    $rows[] = array(array('data' => form_render($form['categories'][$data->nid]), 'align' => 'center'), $data->title, array('data' => $data->nid, 'align' => 'center'), array('data' => $data->cid_count, 'align' => 'center'));
+    $rows[] = array(array('data' => drupal_render($form['categories'][$data->nid]), 'align' => 'center'), $data->title, array('data' => $data->nid, 'align' => 'center'), array('data' => $data->cid_count, 'align' => 'center'));
   }
 
   if (empty($rows)) {
@@ -728,13 +755,13 @@ function theme_category_legacy_export_bo
   $output .= theme('pager', NULL, 50, 0);
 
   if (!empty($containers)) {
-    $output .= form_render($form);
+    $output .= drupal_render($form);
   }
 
   return $output;
 }
 
-function category_legacy_export_taxonomy_validate($form_id, $form_values) {
+function category_legacy_export_taxonomy_form_validate($form_id, $form_values) {
   $containers_selected = FALSE;
 
   if (isset($form_values['categories']) && is_array($form_values['categories'])) {
@@ -751,7 +778,7 @@ function category_legacy_export_taxonomy
   }
 }
 
-function category_legacy_export_book_validate($form_id, $form_values) {
+function category_legacy_export_book_form_validate($form_id, $form_values) {
   $containers_selected = FALSE;
 
   if (isset($form_values['categories']) && is_array($form_values['categories'])) {
@@ -772,7 +799,7 @@ function category_legacy_export_book_val
  * Control function for all actions that occur after the user submits the
  * taxonomy export form.
  */
-function category_legacy_export_taxonomy_submit($form_id, $form_values) {
+function category_legacy_export_taxonomy_form_submit($form_id, $form_values) {
   $containers = array();
   $legacy_map = array();
 
@@ -842,7 +869,7 @@ function category_legacy_export_taxonomy
  * Control function for all actions that occur after the user submits the
  * book export form.
  */
-function category_legacy_export_book_submit($form_id, $form_values) {
+function category_legacy_export_book_form_submit($form_id, $form_values) {
   $containers = array();
 
   // Build all category data in one big nested array
@@ -898,7 +925,7 @@ function category_legacy_get_old_vocabul
 
   if (!isset($header)) {
     $header = array(
-      array('data' => t('Selected')),
+      theme('table_select_header_cell'),
       array('data' => t('Title'), 'field' => 'name', 'sort' => 'asc'),
       array('data' => t('VID'), 'field' => 'vid'),
       array('data' => t('No. of terms'), 'field' => 'tid_count'),
@@ -950,7 +977,7 @@ function category_legacy_get_old_books($
 
   if (!isset($header)) {
     $header = array(
-      array('data' => t('Selected')),
+      theme('table_select_header_cell'),
       array('data' => t('Title'), 'field' => 'title', 'sort' => 'asc'),
       array('data' => t('NID'), 'field' => 'nid'),
       array('data' => t('Direct children'), 'field' => 'child_count'),
@@ -1006,7 +1033,7 @@ function category_legacy_get_old_contain
 
   if (!isset($header)) {
     $header = array(
-      array('data' => t('Selected')),
+      theme('table_select_header_cell'),
       array('data' => t('Title'), 'field' => 'title', 'sort' => 'asc'),
       array('data' => t('NID'), 'field' => 'nid'),
       array('data' => t('No. of categories'), 'field' => 'cid_count'),
@@ -1192,7 +1219,7 @@ function category_legacy_build_container
 
   $node->title = $node->name;
   unset($node->name);
-  $node->type = 'category-cont';
+  $node->type = 'category_cont';
   $node->has_relations = $node->relations;
   unset($node->relations);
   if ($node->module == 'taxonomy') {
@@ -1217,7 +1244,7 @@ function category_legacy_build_container
 function category_legacy_build_container_from_book($book) {
   $node = (object) $book;
 
-  $node->type = 'category-cont';
+  $node->type = 'category_cont';
   $node->module = 'category';
   $node->help = '';
   $node->description = '';
@@ -1301,7 +1328,7 @@ function category_legacy_build_category_
 
   $node->title = $node->name;
   unset($node->name);
-  $node->type = 'category-cat';
+  $node->type = 'category_cat';
   $node->cnid = $cnid;
 
   db_query('UPDATE {node} SET type = \'%s\' WHERE nid = %d', $node->type, $node->nid);
@@ -1343,7 +1370,7 @@ function category_legacy_build_category_
 function category_legacy_build_category_from_book($book, $cnid) {
   $node = (object) $book;
 
-  $node->type = 'category-cat';
+  $node->type = 'category_cat';
   $node->cnid = $cnid;
 
   $node->parents = array($node->parent);
@@ -1449,7 +1476,6 @@ function _category_legacy_build_node($no
   // Force defaults
   $node_options = variable_get('node_options_'. $node->type, array('status', 'promote'));
   $node->status = in_array('status', $node_options);
-  $node->moderate = in_array('moderate', $node_options);
   $node->promote = in_array('promote', $node_options);
   $node->sticky = in_array('sticky', $node_options);
   $node->revision = in_array('revision', $node_options);
Index: category_menu/category_menu.info
===================================================================
RCS file: category_menu/category_menu.info
diff -N category_menu/category_menu.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ category_menu/category_menu.info	5 Jan 2007 15:20:52 -0000
@@ -0,0 +1,5 @@
+; $Id$
+name = Category menu
+description = Creates and manages a set of menu items that correspond to your site's category hierarchy.
+package = Category
+dependencies = category
Index: category_menu/category_menu.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/category/category_menu/category_menu.module,v
retrieving revision 1.37
diff -u -p -r1.37 category_menu.module
--- category_menu/category_menu.module	14 Nov 2006 06:14:50 -0000	1.37
+++ category_menu/category_menu.module	5 Jan 2007 15:20:53 -0000
@@ -11,8 +11,6 @@
  */
 function category_menu_help($section) {
   switch ($section) {
-    case 'admin/modules#description':
-      return t('Creates and manages a set of menu items that correspond to your site\'s category hierarchy. Requires the category module.');
     case 'admin/help#category_menu':
       return t('<p>The category menu module creates and manages a set of menu items that correspond to your site\'s category hierarchy. These menu items are static rather than dynamic, so that you can add other menu items (such as module index pages) as children using the menu module. Breadcrumbs for category and container pages (and, optionally, assigned node pages) will reflect the managed menu items. You can also display the menu as a block on your site.</p><p>This module requires the category module.</p>');
   }
Index: contrib/cac_lite/cac_lite.info
===================================================================
RCS file: contrib/cac_lite/cac_lite.info
diff -N contrib/cac_lite/cac_lite.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/cac_lite/cac_lite.info	5 Jan 2007 15:20:53 -0000
@@ -0,0 +1,5 @@
+; $Id$
+name = Category access control lite
+description = Simple access control based on categories.
+package = Category
+dependencies = category
Index: contrib/cac_lite/cac_lite.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/category/contrib/cac_lite/cac_lite.module,v
retrieving revision 1.6
diff -u -p -r1.6 cac_lite.module
--- contrib/cac_lite/cac_lite.module	6 Nov 2006 01:29:59 -0000	1.6
+++ contrib/cac_lite/cac_lite.module	5 Jan 2007 15:20:53 -0000
@@ -1,11 +1,11 @@
 <?php
 
 /**
- * @file 
- * 
+ * @file
+ *
  * This module provides a simple access control mechanism based
  * on categories, roles and users.
- * 
+ *
  */
 /*
 CAVEAT
@@ -25,7 +25,7 @@ shouldn't have problems.
 For more detailed info, read on...
 
 Because Category uses nodes themselves to define categories,
-you may encounter a small chicken and egg problem.  
+you may encounter a small chicken and egg problem.
 
 Let's say you create a container called "Privacy" and you enter three
 categories in it, "My Eyes Only", "Authenticated Users" and "General
@@ -58,23 +58,20 @@ database.  It's a pain, but that's how i
  */
 function cac_lite_help($section) {
   switch ($section) {
-  case 'admin/modules#description':
-	return t('Simple access control based on categories.');
-	break;
   case 'admin/help#cac_lite':
 	$output .= '<p>'.t('This module allows you to restrict access to site content.  It uses a simple scheme based on Categories (the Category module, not the Taxonomy module), Users and Roles.  It uses the node_access table and other features built into Drupal to hide content from unauthorized users.')."</p>\n";
 	$output .= '<p>'.t('While this module has been designed to be as simple as possible to use, there are several steps required to set it up.')."</p>\n";
 	$output .= "<ol>\n";
 	$output.= '<li>'.t('Define one or more categories whose terms will control which users have access.  For example, you could define a category called \'Privacy\' with terms \'Public\' and \'Private\'.')."</li>\n";
-	$output .= '<li>'.t('Tell this module which category or categories control privacy. (%link)', array('%link' => l(t('administer -> access control -> cac_lite'), 'admin/access/cac_lite')))."</li>\n";
-	$output .= '<li>'.t('Grant access to users based on their roles (%link), and/or...', array('%link' => l(t('administer -> access -> cac_lite -> by role'), 'admin/access/cac_lite/roles')))."</li>\n";
+	$output .= '<li>'.t('Tell this module which category or categories control privacy. (!link)', array('!link' => l(t('administer -> access control -> cac_lite'), 'admin/access/cac_lite')))."</li>\n";
+	$output .= '<li>'.t('Grant access to users based on their roles (!link), and/or...', array('!link' => l(t('administer -> access -> cac_lite -> by role'), 'admin/access/cac_lite/roles')))."</li>\n";
 	$output .= '<li>'.t('Grant access to individual users.  (See the cac_lite tab under user -> edit.)')."</li>\n";
 	$output .= '<li>'.t('Finally, if your site contains content, you will need to re-save all nodes.  This ensures that Drupal\'s node_access table is up-to-date.  Otherwise, content submitted before this module was configured will be hidden.')."</li>\n";
 	$output .= "</ol>\n";
 	$output .= '<p>'.t('Currently, this module works with view grants only (no update or delete grants).')."</p>\n";
 	return $output;
 	break;
-  }  
+  }
 }
 
 
@@ -95,9 +92,9 @@ function cac_lite_menu($may_cache) {
 
   if ($may_cache) {
 
-	$items[] = array('path' => 'admin/access/cac_lite', 
+	$items[] = array('path' => 'admin/access/cac_lite',
 					 'title' => t('cac_lite'),
-					 'callback' => 'cac_lite_admin_settings', 
+					 'callback' => 'cac_lite_admin_settings',
 					 'access' => $admin_access,
 					 'type' => MENU_LOCAL_TASK,
 					 'weight' => 1, // after 'roles' tab
@@ -109,10 +106,10 @@ function cac_lite_menu($may_cache) {
 					 );
 	$items[] = array('path' => 'admin/access/cac_lite/roles',
 					 'title' => t('access by role'),
-					 'callback' => 'cac_lite_admin_settings_defaults', 
+					 'callback' => 'cac_lite_admin_settings_defaults',
 					 'access' => $admin_access,
 					 'type' => MENU_LOCAL_TASK
-					 );					 
+					 );
 
   }
 
@@ -126,7 +123,7 @@ function cac_lite_admin_settings() {
 	$options[$key] = $value->title;
   }
 
-  $form['cac_lite_containers'] = 
+  $form['cac_lite_containers'] =
 	 array('#type' => 'select',
 		   '#title' => 'Containers',
 		   '#default_value' => variable_get('cac_lite_containers', null),
@@ -148,19 +145,19 @@ function cac_lite_admin_settings_default
 
   if (count($cids)) {
 	$all_defaults = variable_get('cac_lite_default_grants', array());
-	$form['cac_lite_default_grants'] = 
+	$form['cac_lite_default_grants'] =
 	  array('#tree' => true);
 	foreach ($roles as $rid => $role_name) {
-	  $form['cac_lite_default_grants'][$rid] = 
+	  $form['cac_lite_default_grants'][$rid] =
 		array('#type' => 'fieldset',
 			  '#tree' => true,
 			  '#title' => t('Access for %role', array('%role' => $role_name)),
-			  // '#description' => t('Users of the \'%role\' role will have these privileges <i>in addition to</i> rights you grant them individually.', array('%role' => $role_name)),			 
+			  // '#description' => t('Users of the \'%role\' role will have these privileges <i>in addition to</i> rights you grant them individually.', array('%role' => $role_name)),
 			  );
 	  $defaults = $all_defaults[$rid];
 	  foreach ($cids as $vid) {
 		$v = category_get_category($vid);
-		$form['cac_lite_default_grants'][$rid][$vid] = 
+		$form['cac_lite_default_grants'][$rid][$vid] =
 		  _category_node_select($v->title,
 								$defaults[$vid],
 								$vid,
@@ -175,7 +172,7 @@ function cac_lite_admin_settings_default
 	return $output;
   }
   else {
-	print theme('page', 
+	print theme('page',
 				t('First select vocabularies on the cac_lite settings page.'));
   }
 }
@@ -190,7 +187,7 @@ function cac_lite_user($op, $edit, $acco
   global $user;
   if (!user_access('administer_cac_lite'))
 	return;
-  
+
   switch ($op) {
   case 'categories':
 	return array(array('name' => 'cac_lite',
@@ -205,7 +202,7 @@ function cac_lite_user($op, $edit, $acco
 	  if (count($vids)) {
 		foreach ($vids as $vid) {
 		  $v = category_get_category($vid);
-		  $form['cac_lite']['cac_lite'][$vid] = 
+		  $form['cac_lite']['cac_lite'][$vid] =
 			 _category_node_select($v->title,
 								   $account->cac_lite[$vid],
 								   $vid,
@@ -214,10 +211,10 @@ function cac_lite_user($op, $edit, $acco
 								   '<'.t('none').'>');
 		}
 	  }
-	  $form['cac_lite'][0] = 
+	  $form['cac_lite'][0] =
 		array('#type' => 'markup',
-			  '#value' => '<p>'.t('You may grant this user view access to any of the terms below.  These grants are in addition to %grant_per_role_link.',
-								  array('%grant_per_role_link' => l(t('access granted to the user by virtue of his/her roles'), 'admin/access/cac_lite/roles'))) . "</p>\n",
+			  '#value' => '<p>'.t('You may grant this user view access to any of the terms below.  These grants are in addition to !grant_per_role_link.',
+								  array('!grant_per_role_link' => l(t('access granted to the user by virtue of his/her roles'), 'admin/access/cac_lite/roles'))) . "</p>\n",
 			  '#weight' => -1);
 	  $form['cac_lite']['cac_lite']['#tree'] = true;
 	  return $form;
@@ -275,7 +272,7 @@ function _cac_lite_node_save(&$node) {
 			 $node->nid,
 			 $node->nid,
 			 'cac_lite',
-			 1, 0, 0);	
+			 1, 0, 0);
 	$access_restricted = true;
   }
 
@@ -296,7 +293,7 @@ function _cac_lite_node_save(&$node) {
 				 $node->nid,
 				 $cid,
 				 'cac_lite',
-				 1, 0, 0);	
+				 1, 0, 0);
 		$access_restricted = true;
 	  }
 	}
@@ -323,7 +320,7 @@ function _cac_lite_node_save(&$node) {
 				 $node->nid,
 				 $gid,
 				 'cac_lite',
-				 1, 0, 0);	
+				 1, 0, 0);
 		$access_restricted = true;
 	  }
 	}
@@ -339,8 +336,8 @@ function _cac_lite_node_save(&$node) {
 			   $node->nid,
 			   0, // gid = 0 means all users access
 			   'cac_lite',
-			   1, 0, 0);	
-	  
+			   1, 0, 0);
+
 	}
   }
 }
@@ -362,7 +359,7 @@ function _cac_lite_user_tids(&$account) 
 	  $grants = array_merge($grants, $tids);
 	}
   }
-  
+
   // add default grants in addition to user-specific grants
   $defaults = variable_get('cac_lite_default_grants', array());
   foreach ($account->roles as $rid => $role_name) {
@@ -372,11 +369,11 @@ function _cac_lite_user_tids(&$account) 
 	  }
 	}
   }
-  
+
   // grant id 0 is reserved for nodes which were not given a grant id when they were created.  By adding 0 to the grant id, we let the user view those nodes.
   // TODO: make this behavior configurable, to play nicely with other node_access modules which may be installed
   $grants[] = 0;
-  
+
   return $grants;
 }
 
@@ -387,9 +384,9 @@ function cac_lite_node_grants(&$account,
 	$all = array(0);
   else
 	$all = array(-1);
-  
+
   $grants = _cac_lite_user_tids($account);
-  
+
   // TODO: differentiate between view, update, delete
   return array('all' => $all, // this disables the default setting (view all)
 			   'cac_lite' => $grants);
@@ -420,7 +417,7 @@ function cac_lite_db_rewrite_sql($query,
 	// making this clause probably unnecessary.  Worth looking into
 	// later.  For now I do not want to change working code.
     $join = "LEFT JOIN {category} ca_c ON $primary_table.cid = ca_c.cid";
-    $where = "($primary_table.cid IN (". implode(', ', $tids) .") OR ca_c.cnid NOT IN (". implode(',', $vids) ."))"; 
+    $where = "($primary_table.cid IN (". implode(', ', $tids) .") OR ca_c.cnid NOT IN (". implode(',', $vids) ."))";
 
 	// Categories are also nodes.  So we need a clause that inspects
 	// the node_access table to see if the user can see these
Index: contrib/category_bulkedit/category_bulkedit.info
===================================================================
RCS file: contrib/category_bulkedit/category_bulkedit.info
diff -N contrib/category_bulkedit/category_bulkedit.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/category_bulkedit/category_bulkedit.info	5 Jan 2007 15:20:53 -0000
@@ -0,0 +1,5 @@
+; $Id$
+name = Category bulk edit
+description = Provides an interface for editing multiple categories or containers at once.
+package = Category
+dependencies = category
Index: contrib/category_bulkedit/category_bulkedit.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/category/contrib/category_bulkedit/category_bulkedit.module,v
retrieving revision 1.9
diff -u -p -r1.9 category_bulkedit.module
--- contrib/category_bulkedit/category_bulkedit.module	10 Jul 2006 05:44:58 -0000	1.9
+++ contrib/category_bulkedit/category_bulkedit.module	5 Jan 2007 15:20:54 -0000
@@ -15,13 +15,11 @@
  */
 function category_bulkedit_help($section) {
   switch ($section) {
-    case 'admin/modules#description':
-      return t('Provides an interface for editing multiple categories or containers at once. Requires the category module.');
-    case 'admin/category/bulkedit':
+    case 'admin/content/category/bulkedit':
       return _category_bulkedit_set_help_text();
   }
 
-  if (preg_match('/^admin\/category\/\d+\/bulkedit$/', $section)) {
+  if (preg_match('/^admin\/content\/category\/\d+\/bulkedit$/', $section)) {
     return _category_bulkedit_set_help_text();
   }
 }
@@ -34,22 +32,23 @@ function category_bulkedit_menu($may_cac
 
   if ($may_cache) {
     $items[] = array(
-      'path' => 'admin/category/bulkedit',
-      'title' => t('bulk edit'),
-      'callback' => 'category_bulkedit_form',
+      'path' => 'admin/content/category/bulkedit',
+      'title' => t('Bulk edit'),
+      'callback' => 'drupal_get_form',
+      'callback arguments' => array('category_bulkedit_form', 'category_cont', NULL),
       'access' => user_access('administer categories'),
       'type' => MENU_LOCAL_TASK,
       'weight' => 8,
     );
   }
   else {
-    if (arg(0) == 'admin' && arg(1) == 'category' && is_numeric(arg(2))) {
-      $nid = arg(2);
+    if (arg(0) == 'admin' && arg(2) == 'category' && is_numeric(arg(3))) {
+      $nid = arg(3);
       $items[] = array(
-        'path' => 'admin/category/'. $nid .'/bulkedit',
-        'title' => t('bulk edit'),
-        'callback' => 'category_bulkedit_form',
-        'callback arguments' => array('category-cat', $nid),
+        'path' => 'admin/content/category/'. $nid .'/bulkedit',
+        'title' => t('Bulk edit'),
+        'callback' => 'drupal_get_form',
+        'callback arguments' => array('category_bulkedit_form', 'category_cat', $nid),
         'access' => user_access('administer categories'),
         'type' => MENU_LOCAL_TASK,
         'weight' => 8,
@@ -62,244 +61,367 @@ function category_bulkedit_menu($may_cac
 
 /**
  * Displays the multipage form for bulk editing of categories or containers.
- * We set the 'real' #required attribute values here, but the final value of
- * #required attributes is handled by category_bulkedit_pre_render().
  */
-function category_bulkedit_form($type = 'category-cont', $cnid = NULL) {
-  global $form_values;
+function category_bulkedit_form($type = 'category_cont', $cnid = NULL, $form_values = NULL) {
   $form = array();
-  $is_cat = is_numeric(arg(2));
+  $is_cat = is_numeric(arg(3));
 
-  // Helper for our multipage - does field switching, sets options
-  // based on validated $form_values instead of $_POST, and so forth.
-  $form['#pre_render'] = array('category_bulkedit_pre_render');
-
-  // Category / container selection, page 1
-  $list_items = array();
-  if ($type == 'category-cont') {
-    $containers = category_get_containers();
-    foreach ($containers as $value) {
-      $list_items[$value->cid] = $value->admin_title;
-    }
+  // In a multistep form, drupal_get_form() will always
+  // pass the incoming form values to you after any other
+  // parameters that you specify manually. Do this instead
+  // of looking at the incoming $_POST variable manually.
+
+  if (!isset($_POST['op'])) {
+    $step = 1;
+    $_SESSION['category_bulkedit'] = NULL;
   }
-  else {
-    $categories = category_get_tree($cnid);
-    foreach ($categories as $value) {
-      $list_items[$value->cid] = $value->title;
-    }
+  elseif ($form_values['op'] == t('Back')) {
+    $step = $form_values['step'] - 1;
   }
-  foreach ($list_items as $nid => $title) {
-    $form['bulkedit'][$nid] = array(
-      '#type' => 'checkbox',
-    );
-    $form['titles'][$nid] = array(
-      '#type' => 'markup',
-      '#value' => l($title, 'node/'. $nid),
-    );
-    $form['nids'][$nid] = array(
-      '#type' => 'markup',
-      '#value' => $nid,
-    );
+  else {
+    $step = $form_values['step'] + 1;
   }
 
-  $form['bulkedit']['#tree'] = TRUE;
-  $form['titles']['#tree'] = TRUE;
-  $form['nids']['#tree'] = TRUE;
-
-  // Field selection, page 2
-  $editing_form = category_get_form($is_cat, NULL, FALSE);
-  _category_bulkedit_set_editing_fields($editing_form);
-  $field_selections = _category_bulkedit_get_field_selections($editing_form);
-
-  foreach ($field_selections as $field => $value) {
-    $form['bulkedit_fields'][$field] = array(
-      '#type' => 'checkbox',
-    );
-    $form['field_titles'][$field] = array(
-      '#type' => 'markup',
-      '#value' => $value['title'],
-    );
-    $form['field_types'][$field] = array(
-      '#type' => 'markup',
-      '#value' => $value['type'],
-    );
-    $form['field_groups'][$field] = array(
-      '#type' => 'markup',
-      '#value' => implode(' -> ', $value['groups']),
-    );
-  }
-  $form['bulkedit_fields']['#tree'] = TRUE;
-  $form['field_titles']['#tree'] = TRUE;
-  $form['field_types']['#tree'] = TRUE;
-  $form['field_groups']['#tree'] = TRUE;
-
-  // Form field editing, page 3
-  $form += $editing_form;
-
-  // Add a back button
-  $form['back'] = array(
-    '#type'          => 'button',
-    '#value'         => t('Back'),
-    '#weight'        => 35,
+  $form['step'] = array(
+    '#type' => 'hidden',
+    '#value' => $step,
   );
+  $form['#theme'] = 'category_bulkedit_form_step'. $step;
+
+  switch ($step) {
+    case 1:
+    case 2:
+    case 4:
+      // Category / container selection, page 1
+      $list_items = array();
+      if ($type == 'category_cont') {
+        $containers = category_get_containers();
+        foreach ($containers as $value) {
+          $list_items[$value->cid] = $value->admin_title;
+        }
+      }
+      else {
+        $categories = category_get_tree($cnid);
+        foreach ($categories as $value) {
+          $list_items[$value->cid] = $value->title;
+        }
+      }
+      foreach ($list_items as $nid => $title) {
+        if ($step == 1) {
+          $form['bulkedit'][$nid] = array(
+            '#type' => 'checkbox',
+            '#default_value' => !empty($_SESSION['category_bulkedit']['step_1']['bulkedit'][$nid]) ? 1 : 0,
+          );
+          $form['nids'][$nid] = array(
+            '#type' => 'markup',
+            '#value' => $nid,
+          );
+        }
+        if ($step == 1 || $step == 4) {
+          $form['titles'][$nid] = array(
+            '#type' => 'markup',
+            '#value' => l($title, 'node/'. $nid),
+          );
+        }
+      }
+
+      if ($step == 1) {
+        $form['bulkedit']['#tree'] = TRUE;
+        $form['nids']['#tree'] = TRUE;
+      }
+      if ($step == 1 || $step == 4) {
+        // Add a back button
+        $form['back'] = array(
+          '#type'          => 'button',
+          '#value'         => t('Back'),
+          '#weight'        => 35,
+        );
+        $form['titles']['#tree'] = TRUE;
+      }
+
+      // Field selection, page 2
+      $editing_form = category_get_form($is_cat, NULL, FALSE);
+      $field_selections = _category_bulkedit_get_field_selections($editing_form);
+
+      foreach ($field_selections as $field => $value) {
+        if ($step == 2) {
+          $form['bulkedit_fields'][$field] = array(
+            '#type' => 'checkbox',
+            '#default_value' => !empty($_SESSION['category_bulkedit']['step_2']['bulkedit_fields'][$field]) ? 1 : 0,
+          );
+          $form['field_types'][$field] = array(
+            '#type' => 'markup',
+            '#value' => $value['type'],
+          );
+          $form['field_groups'][$field] = array(
+            '#type' => 'markup',
+            '#value' => implode(' -> ', $value['groups']),
+          );
+        }
+        if ($step == 2 || $step == 4) {
+          $form['field_titles'][$field] = array(
+            '#type' => 'markup',
+            '#value' => $value['title'],
+          );
+        }
+      }
+      if ($step == 2) {
+        $form['bulkedit_fields']['#tree'] = TRUE;
+        $form['field_types']['#tree'] = TRUE;
+        $form['field_groups']['#tree'] = TRUE;
+      }
+      if ($step == 2 || $step == 4) {
+        $form['field_titles']['#tree'] = TRUE;
+      }
+
+      if ($step == 2) {
+        // Add a back button
+        $form['back'] = array(
+          '#type'          => 'button',
+          '#value'         => t('Back'),
+          '#weight'        => 35,
+        );
+      }
+      break;
+
+    case 3:
+      // Form field editing, page 3
+      $editing_form = category_get_form($is_cat, (!empty($_SESSION['category_bulkedit']['step_3']) ? (object) $_SESSION['category_bulkedit']['step_3'] : NULL), FALSE);
+      foreach (element_children($editing_form) as $fieldset_key) {
+        foreach (element_children($editing_form[$fieldset_key]) as $form_key) {
+          if (empty($_SESSION['category_bulkedit']['step_2']['bulkedit_fields'][$form_key])) {
+            unset($editing_form[$fieldset_key][$form_key]);
+          }
+        }
+      }
+      _category_bulkedit_check_fieldsets($editing_form);
+
+      $form += $editing_form;
+
+      // Add a back button
+      $form['back'] = array(
+        '#type'          => 'button',
+        '#value'         => t('Back'),
+        '#weight'        => 35,
+      );
+      break;
+  }
+
+  // This part is important!
+  $form['#multistep'] = TRUE;
+  $form['#redirect'] = FALSE;
 
   // Also a submit button (since this is not the node form, none has been
   // provided for us)
+  $submit_text = array(NULL, t('Next (field selection)'), t('Next (field editing)'), t('Next (preview changes)'), t('Run bulk edit'));
   $form['submit'] = array(
     '#type' => 'submit',
-    '#value' => t('Run bulk edit'),
+    '#value' =>  $submit_text[$step],
     '#weight' => 45
   );
 
-  return drupal_get_form('category_bulkedit_form' ,$form);
+  return $form;
 }
 
 /*
- * Themes the multipage form differently, depending on the page currently being
- * viewed.
+ * Themes the multipage form for step 1.
  */
-function theme_category_bulkedit_form($form) {
-  global $form_values;
-
+function theme_category_bulkedit_form_step1($form) {
   $content = '';
-  $is_cat = is_numeric(arg(2));
+  $is_cat = is_numeric(arg(3));
 
-  if (in_array($form['page']['#value'], array(1))) {
-    $rows = array();
+  $rows = array();
 
-    $elements = element_children($form['nids']);
-    if (!empty($elements)) {
-      foreach ($elements as $key) {
-        $row = array();
-        $row[] = array('data' => form_render($form['bulkedit'][$key]), 'align' => 'center');
-        $row[] = form_render($form['titles'][$key]);
-        $row[] = array('data' => form_render($form['nids'][$key]), 'align' => 'center');
+  $elements = element_children($form['nids']);
+  if (!empty($elements)) {
+    foreach ($elements as $key) {
+      $row = array();
+      $form['bulkedit'][$key]['#value'] = $form['bulkedit'][$key]['#default_value'];
+      $row[] = drupal_render($form['bulkedit'][$key]);
+      $row[] = drupal_render($form['titles'][$key]);
+      $row[] = drupal_render($form['nids'][$key]);
 
-        $rows[] = $row;
-      }
-    }
-    else {
-      $rows[] = array(array('data' => t('No %items available', array('%items' => $is_cat ? t('categories') : t('containers'))), 'colspan' => 3));
-      unset($form['submit']);
+      $rows[] = $row;
     }
+  }
+  else {
+    $rows[] = array(array('data' => t('No @items available', array('@items' => $is_cat ? t('categories') : t('containers'))), 'colspan' => 3));
+    unset($form['submit']);
+  }
 
-    $header = array(t('Selected'), t('Title'), t('Node ID'));
+  $header = array(theme('table_select_header_cell'), t('Title'), t('Node ID'));
 
-    $content .= theme('table', $header, $rows);
-  }
-  elseif (in_array($form['page']['#value'], array(2))) {
-    $rows = array();
+  $content .= theme('table', $header, $rows);
 
-    $elements = element_children($form['bulkedit_fields']);
-    if (!empty($elements)) {
-      foreach ($elements as $key) {
-        $row = array();
-        $row[] = array('data' => form_render($form['bulkedit_fields'][$key]), 'align' => 'center');
-        $row[] = form_render($form['field_titles'][$key]);
-        $row[] = form_render($form['field_types'][$key]);
-        $row[] = form_render($form['field_groups'][$key]);
+  $content .= drupal_render($form);
 
-        $rows[] = $row;
-      }
-    }
-    else {
-      $rows[] = array(array('data' => t('No fields available'), 'colspan' => 4));
-      unset($form['submit']);
+  _category_bulkedit_set_help_text(1, $is_cat);
+
+  return $content;
+}
+
+/*
+ * Themes the multipage form for step 2.
+ */
+function theme_category_bulkedit_form_step2($form) {
+  $content = '';
+  $is_cat = is_numeric(arg(3));
+
+  $rows = array();
+
+  $elements = element_children($form['bulkedit_fields']);
+  if (!empty($elements)) {
+    foreach ($elements as $key) {
+      $row = array();
+      $form['bulkedit_fields'][$key]['#value'] = $form['bulkedit_fields'][$key]['#default_value'];
+      $row[] = drupal_render($form['bulkedit_fields'][$key]);
+      $row[] = drupal_render($form['field_titles'][$key]);
+      $row[] = drupal_render($form['field_types'][$key]);
+      $row[] = drupal_render($form['field_groups'][$key]);
+
+      $rows[] = $row;
     }
+  }
+  else {
+    $rows[] = array(array('data' => t('No fields available'), 'colspan' => 4));
+    unset($form['submit']);
+  }
 
-    $header = array(t('Selected'), t('Title'), t('Type'), t('Group(s)'));
+  $header = array(theme('table_select_header_cell'), t('Title'), t('Type'), t('Group(s)'));
 
-    $content .= theme('table', $header, $rows);
+  $content .= theme('table', $header, $rows);
+
+  $content .= drupal_render($form);
+
+  _category_bulkedit_set_help_text(2, $is_cat);
+
+  return $content;
+}
+
+/*
+ * Themes the multipage form for step 3.
+ */
+function theme_category_bulkedit_form_step3($form) {
+  $content = drupal_render($form);
+
+  _category_bulkedit_set_help_text(3, $is_cat);
+
+  return $content;
+}
+
+/*
+ * Themes the multipage form for step 4.
+ */
+function theme_category_bulkedit_form_step4($form) {
+  $content = '';
+  $is_cat = is_numeric(arg(3));
+
+  drupal_add_css(drupal_get_path('module', 'category_bulkedit'). '/category_bulkedit.css');
+
+  // Nodes to be edited - display
+  $rows = array();
+
+  $items = array();
+  if (!empty($_SESSION['category_bulkedit']['step_1']['bulkedit'])) {
+    foreach (element_children($_SESSION['category_bulkedit']['step_1']['bulkedit']) as $bulkedit_key) {
+      if (!empty($_SESSION['category_bulkedit']['step_1']['bulkedit'][$bulkedit_key])) {
+        $items[$bulkedit_key] = $_SESSION['category_bulkedit']['step_1']['bulkedit'][$bulkedit_key];
+      }
+    }
   }
-  elseif (in_array($form['page']['#value'], array(4))) {
-    theme_add_style(drupal_get_path('module', 'category_bulkedit'). '/category_bulkedit.css');
-
-    // Nodes to be edited - display
-    $rows = array();
-
-    $items = array_filter($form_values['bulkedit']);
-    $num_cols = 3;
-    if (!empty($items)) {
-      $total = count($items);
-      $one_row = $total < $num_cols;
-      $num_lists = $one_row ? $total : $num_cols;
-      $offset = $one_row ? 1 : floor($total / $num_cols);
-      $offset_less = 0;
-      $remainder = $total % $num_cols;
-      $items_formatted = array();
-
-      foreach ($items as $key => $value) {
-        $item_formatted = form_render($form['titles'][$key]);
-        if (isset($form['titles'][$key])) {
-          $items_formatted[] = $item_formatted;
-        }
-      }
-      unset($form['titles']);
-
-      $item_output = '<p><strong>'. t('%items to be bulk edited:', array('%items' => ($is_cat ? t('Categories') : t('Containers')))). "</strong></p>\n";
-
-      $count = 0;
-      while ($count < $num_lists) {
-        $item_output .= "<ul class=\"category-bulkedit-floated-list\">\n<li>";
-        $items_slice = NULL;
-        $curr_offset = ($count * $offset) + $offset_less;
-        $curr_length = $offset;
-        if ($remainder && !$one_row) {
-          $curr_length++;
-          $remainder--;
-          $offset_less++;
-        }
-        if ($num_cols - $count > 1) {
-          $items_slice = array_slice($items_formatted, $curr_offset, $curr_length);
-        }
-        else {
-          $items_slice = array_slice($items_formatted, $curr_offset);
-        }
-        $item_output .= implode("</li>\n<li>", $items_slice);
-        $item_output .= "</li>\n</ul>\n";
 
-        $count++;
+  $num_cols = 3;
+  if (!empty($items)) {
+    $total = count($items);
+    $one_row = $total < $num_cols;
+    $num_lists = $one_row ? $total : $num_cols;
+    $offset = $one_row ? 1 : floor($total / $num_cols);
+    $offset_less = 0;
+    $remainder = $total % $num_cols;
+    $items_formatted = array();
+
+    foreach ($items as $key => $value) {
+      $item_formatted = drupal_render($form['titles'][$key]);
+      if (isset($form['titles'][$key])) {
+        $items_formatted[] = $item_formatted;
+      }
+    }
+    unset($form['titles']);
+
+    $item_output = '<p><strong>'. t('@items to be bulk edited:', array('@items' => ($is_cat ? t('Categories') : t('Containers')))). "</strong></p>\n";
+
+    $count = 0;
+    while ($count < $num_lists) {
+      $item_output .= "<ul class=\"category-bulkedit-floated-list\">\n<li>";
+      $items_slice = NULL;
+      $curr_offset = ($count * $offset) + $offset_less;
+      $curr_length = $offset;
+      if ($remainder && !$one_row) {
+        $curr_length++;
+        $remainder--;
+        $offset_less++;
+      }
+      if ($num_cols - $count > 1) {
+        $items_slice = array_slice($items_formatted, $curr_offset, $curr_length);
+      }
+      else {
+        $items_slice = array_slice($items_formatted, $curr_offset);
       }
+      $item_output .= implode("</li>\n<li>", $items_slice);
+      $item_output .= "</li>\n</ul>\n";
 
-      $content .= $item_output;
+      $count++;
     }
 
-    // Fields and values to be edited - display
-    $fields = array_filter($form_values['bulkedit_fields']);
-    $field_output = '<p class="category-bulkedit-clear"><strong>'. t('Fields to be bulk edited, and values to be saved:'). "</strong></p>\n";
-
-    $rows = array();
-    _category_bulkedit_flatten_fields_copy($form);
+    $content .= $item_output;
+  }
 
-    if (!empty($fields)) {
-      foreach ($fields as $key => $value) {
-        $row = array();
-        $row[] = form_render($form['field_titles'][$key]);
-        $form[$key]['#theme'] = 'category_bulkedit_field_preview';
-        theme('category_bulkedit_field_preview', $form[$key], TRUE);
-        $form[$key]['#type'] = 'markup';
-        $form[$key]['#value'] = NULL;
-        $row[] = check_plain(form_render($form[$key]));
-        $rows[] = $row;
+  // Fields and values to be edited - display
+  $fields = array();
+  if (!empty($_SESSION['category_bulkedit']['step_2']['bulkedit_fields'])) {
+    foreach (element_children($_SESSION['category_bulkedit']['step_2']['bulkedit_fields']) as $bulkedit_key) {
+      if (!empty($_SESSION['category_bulkedit']['step_2']['bulkedit_fields'][$bulkedit_key])) {
+        $fields[$bulkedit_key] = $_SESSION['category_bulkedit']['step_2']['bulkedit_fields'][$bulkedit_key];
       }
-      unset($form['field_titles']);
     }
-    else {
-      $rows[] = array(array('data' => t('No fields available'), 'colspan' => 2));
-      unset($form['submit']);
+  }
+  $field_output = '<p class="category-bulkedit-clear"><strong>'. t('Fields to be bulk edited, and values to be saved:'). "</strong></p>\n";
+
+  $rows = array();
+  _category_bulkedit_flatten_fields_copy($form);
+
+  if (!empty($fields)) {
+    $editing_form = category_get_form($is_cat, NULL, FALSE);
+    $field_selections = _category_bulkedit_get_field_selections($editing_form);
+
+    foreach ($fields as $key => $value) {
+      $row = array();
+      $row[] = $field_selections[$key]['title'];
+      $form[$key]['#theme'] = 'category_bulkedit_field_preview';
+      theme('category_bulkedit_field_preview', $form[$key], TRUE);
+      $form[$key]['#type'] = 'markup';
+      $form[$key]['#value'] = NULL;
+      drupal_render($form[$key]);
+      $row[] = check_plain($_SESSION['category_bulkedit']['step_3'][$key]);
+      $rows[] = $row;
     }
+    unset($form['field_titles']);
+  }
+  else {
+    $rows[] = array(array('data' => t('No fields available'), 'colspan' => 2));
+    unset($form['submit']);
+  }
 
-    $header = array(t('Field'), t('Value'));
-    $field_output .= theme('table', $header, $rows);
+  $header = array(t('Field'), t('Value'));
+  $field_output .= theme('table', $header, $rows);
 
-    $content .= $field_output;
+  $content .= $field_output;
 
-    $content .= '<p>'. t('When you click the <em>run bulk edit</em> button below, the bulk edit will be performed. The operation may take some time to complete, so please be patient and do not interrupt the process. This operation is <strong>irreversible</strong>, and it will potentially affect a large amount of data on your site. Please ensure that you have thoroughly checked all the information displayed on this page before proceeding.'). "</p>\n";
-  }
+  $content .= '<p>'. t('When you click the <em>run bulk edit</em> button below, the bulk edit will be performed. The operation may take some time to complete, so please be patient and do not interrupt the process. This operation is <strong>irreversible</strong>, and it will potentially affect a large amount of data on your site. Please ensure that you have thoroughly checked all the information displayed on this page before proceeding.'). "</p>\n";
 
-  $content .= form_render($form);
+  $content .= drupal_render($form);
 
-  _category_bulkedit_set_help_text($form['page']['#value'], $is_cat);
+  _category_bulkedit_set_help_text(4, $is_cat);
 
   return $content;
 }
@@ -344,426 +466,116 @@ function theme_category_bulkedit_field_p
 }
 
 /**
- * Implementation of hook_form_alter(). Here, we set up the 'page' field,
- * which keeps track of what stage the form is in.
- */
-function category_bulkedit_form_alter($form_id, &$form) {
-  // Make sure it's our multipage form.
-  if ($form_id == 'category_bulkedit_form') {
-
-    // Determine which page of the multipage form we're on. We don't do
-    // any incrementing here - that's something that our #pre_render'er
-    // will do when this page of the form has successfully validated.
-    $form['page'] = array(
-      '#type' => 'hidden',
-      '#value' => isset($_POST['edit']['page']) ? $_POST['edit']['page'] : 1,
-    );
-
-    // If back button is pressed, back up the form stage, Also, if preview
-    // is hit we need to decrement the counter here to keep us on the same page.
-    if ($_POST['op'] == t('Back')) {
-      $form['page']['#value']--;
-    }
-
-    $editing_fields = _category_bulkedit_set_editing_fields();
-    _category_bulkedit_unset_fields($editing_fields, $form);
-
-    // This modifies the form for validation purposes. once validation is
-    // completed, it'll be called one more time (through Drupal's Form API)
-    // at which point it'll advance the form to the next page.
-    category_bulkedit_pre_render($form_id, $form, FALSE);
-
-    if (!isset($form['#validate'])) {
-      $form['#validate'] = array();
-    }
-    if (!isset($form['#submit'])) {
-      $form['#submit'] = array();
-    }
-    // Here we're augmenting the regular node form validation/submission with
-    // some of our own.  Note that these are inside the conditional check for
-    // this particular form.
-    $form['#validate'] = array_merge($form['#validate'], array('category_bulkedit_custom_validate' => array()));
-    $form['#submit'] = array_merge($form['#submit'], array('category_bulkedit_custom_submit' => array()));
-  }
-
-  return $form;
-}
-
-/**
  * Validate our form.
  */
-function category_bulkedit_custom_validate() {
-  global $form_values;
-  $is_cat = is_numeric(arg(2));
+function category_bulkedit_form_validate($form_id, $form_values) {
+  if (isset($form_values['op']) && $form_values['op'] != t('Back')) {
+    $is_cat = is_numeric(arg(3));
 
-  // validate our number, but don't bother if the back button was hit
-  if ($form_values['page'] ==  1 ) {
-    $items_selected = FALSE;
+    switch ($form_values['step']) {
+      case 1:
+        $items_selected = FALSE;
 
-    if (isset($form_values['bulkedit']) && is_array($form_values['bulkedit'])) {
-      foreach ($form_values['bulkedit'] as $value) {
-        if ($value) {
-          $items_selected = TRUE;
-          break;
+        if (isset($form_values['bulkedit']) && is_array($form_values['bulkedit'])) {
+          foreach ($form_values['bulkedit'] as $value) {
+            if ($value) {
+              $items_selected = TRUE;
+              break;
+            }
+          }
         }
-      }
-    }
 
-    if (!$items_selected) {
-      form_set_error('bulkedit', t('You must select at least one %item.', array('%item' => ($is_cat ? t('category') : t('container')))));
-    }
-  }
-  elseif ($form_values['page'] ==  2 ) {
-    $items_selected = FALSE;
-
-    if (isset($form_values['bulkedit_fields']) && is_array($form_values['bulkedit_fields'])) {
-      foreach ($form_values['bulkedit_fields'] as $value) {
-        if ($value) {
-          $items_selected = TRUE;
-          break;
+        if (!$items_selected) {
+          form_set_error('bulkedit', t('You must select at least one @item.', array('@item' => ($is_cat ? t('category') : t('container')))));
         }
-      }
-    }
-
-    if (!$items_selected) {
-      form_set_error('bulkedit', t('You must select at least one field.'));
-    }
-  }
-}
-
-/**
- * The #pre_render of a form allows us to make changes AFTER validation (unlike
- * hook_form_alter()), but BEFORE the form has actually been displayed. We use
- * it to control which form elements are shown, which are hidden, and which values
- * to set based on validate elements, not $_POST. This is a necessity for our
- * complicated multipage example form.
- */
-function category_bulkedit_pre_render($form_id, &$form, $next_page = TRUE) {
-  global $form_values;
-
-  // Make sure it's our multipage form.
-  if ($form_id == 'category_bulkedit_form') {
-    // Are we ready for the next page in our form?
-    if ($next_page && isset($_POST['edit']['page']) && ($_POST['op'] != t('Back'))) {
-      $form['page']['#value'] = $form['page']['#value'] + 1;
-    }
-
-    // Validation errors? Show previous page for correcting.
-    if (form_get_errors()) {
-      $form['page']['#value']--;
-    }
-
-    // Modify the #required/#type values depending on our current page.
-    // The arrays tell us the pages the changes should take place in.
-
-    // Category/container selection, stage 1
-    category_bulkedit_set_element_visibility($form['bulkedit'],                  in_array($form['page']['#value'], array(1)), $next_page);
-    category_bulkedit_set_element_visibility($form['titles'],                    in_array($form['page']['#value'], array(1, 4)), $next_page);
-    category_bulkedit_set_element_visibility($form['nids'],                      in_array($form['page']['#value'], array(1)), $next_page);
-
-    // Field selection, stage 2
-    category_bulkedit_set_element_visibility($form['bulkedit_fields'],           in_array($form['page']['#value'], array(2)), $next_page);
-    category_bulkedit_set_element_visibility($form['field_titles'],              in_array($form['page']['#value'], array(2, 4)), $next_page);
-    category_bulkedit_set_element_visibility($form['field_types'],               in_array($form['page']['#value'], array(2)), $next_page);
-    category_bulkedit_set_element_visibility($form['field_groups'],              in_array($form['page']['#value'], array(2)), $next_page);
-
-    // Form field editing, page 3
-    $editing_fields = _category_bulkedit_set_editing_fields();
-    _category_bulkedit_set_editing_fields_visibility($editing_fields, $form,     in_array($form['page']['#value'], array(3)), $next_page);
-    _category_bulkedit_check_fieldsets($form);
-
-    // Buttons
-    category_bulkedit_set_element_visibility($form['back'],                      in_array($form['page']['#value'], array(2, 3, 4)), $next_page);
-    category_bulkedit_set_element_visibility($form['submit'],                    in_array($form['page']['#value'], array(4)), $next_page);
-
-    // The button text actually helps determine if a form has actually been
-    // submitted because the name is also the value of a clicked button. By
-    // changing it for building, but not rendering, the form is not fully
-    // sumbitted until we name it 'Submit', the usual value.
-    if ($next_page) {
-      $submit_text = array(NULL, t('Next (field selection)'), t('Next (field editing)'), t('Next (preview changes)'), t('Run bulk edit'));
-      $form['submit']['#value'] = $submit_text[$form['page']['#value']];
-    }
-  }
-}
-
-/*
- * Handles form submission. Goes through all the selected nodes, and for each
- * node, gathers all the values that have been set, and saves the node with
- * those new values.
- */
-function category_bulkedit_custom_submit() {
-  global $form_values;
-  $is_cat = is_numeric(arg(2));
-
-  if (!isset($form_values['parents']) || !is_array($form_values['parents'])) {
-    $form_values['parents'] = array($form_values['parents']);
-  }
-  if (empty($form_values['parents'][0])) {
-    if ($is_cat) {
-      $form_values['parents'][0] = arg(2);
-    }
-    else {
-      unset($form_values['parents'][0]);
-    }
-  }
-  if (!isset($form_values['nodes']) || !is_array($form_values['nodes'])) {
-    $form_values['nodes'] = array($form_values['nodes']);
-  }
-  if (empty($form_values['nodes'][0])) {
-    unset($form_values['nodes'][0]);
-  }
+        break;
 
-  if (isset($form_values['bulkedit']) && is_array($form_values['bulkedit'])) {
-    $saved_count = 0;
-    foreach ($form_values['bulkedit'] as $nid => $value) {
-      if ($value && is_numeric($nid)) {
-        $node = node_load($nid);
+      case 2:
+        $items_selected = FALSE;
 
         if (isset($form_values['bulkedit_fields']) && is_array($form_values['bulkedit_fields'])) {
-          foreach ($form_values['bulkedit_fields'] as $field => $field_value) {
-            if ($field_value) {
-              $node->$field = $form_values[$field];
+          foreach ($form_values['bulkedit_fields'] as $value) {
+            if ($value) {
+              $items_selected = TRUE;
+              break;
             }
           }
         }
 
-        $node->date = date('j M Y H:i:s', $node->created);
-
-        $node = node_submit($node);
-
-        node_save($node);
-        $saved_count++;
-      }
+        if (!$items_selected) {
+          form_set_error('bulkedit', t('You must select at least one field.'));
+        }
+        break;
     }
-
-    drupal_set_message(t('%count %items were successfully bulk edited.', array('%count' => $saved_count, '%items' => ($is_cat ? t('categories') : t('containers')))));
-
-    return 'admin/category'. ($is_cat ? '/'. arg(2) : '');
   }
 }
 
-/**
- * Set an element's visibility. Elements are gnerally changed to hidden
- * elements. Visibility may be set and reset any number of times.
- *
- * @param $element
- *   The form element array to modify.
- * @param $visible
- *   The desired visibity of the form element.
- * @param $next_page
- *   Boolean value, TRUE if the next page is about to be rendered, FALSE otherwise.
+/*
+ * Handles form submission. Goes through all the selected nodes, and for each
+ * node, gathers all the values that have been set, and saves the node with
+ * those new values.
  */
-function category_bulkedit_set_element_visibility(&$element, $visible, $next_page = TRUE) {
-  category_bulkedit_restore_attributes($element);
-  if (!$visible) {
-    switch ($element['#type']) {
-      case 'textfield':
-      case 'textarea':
-        if ($next_page) {
-          category_bulkedit_set_attribute($element, '#type', 'hidden');
-          category_bulkedit_set_attribute($element, '#required', FALSE);
-        }
-        break;
+function category_bulkedit_form_submit($form_id, $form_values) {
+  $is_cat = is_numeric(arg(3));
 
-      case 'radios':
-        // Radios elements cannot be hidden unless they have been processed.
-        if ($next_page) {
-          category_bulkedit_set_attribute($element, '#type', 'hidden');
-        }
-        else {
-          category_bulkedit_set_attribute($element, '#required', FALSE);
-        }
-        break;
-
-      case 'select':
-      case 'activeselect':
-      case 'checkboxes':
-      case 'weight':
-        if ($next_page) {
-          if ($element['#multiple'] || $element['#type'] == 'checkboxes') {
-            category_bulkedit_set_attribute($element, '#type', 'category_bulkedit_hidden_array');
-            $element = category_bulkedit_expand_hidden_array($element);
-            category_bulkedit_set_attribute($element, '#tree', TRUE);
-          }
-          else {
-            category_bulkedit_set_attribute($element, '#type', 'hidden');
-          }
-          category_bulkedit_set_attribute($element, '#processed', TRUE);
+  switch ($form_values['step']) {
+    case 1:
+    case 2:
+    case 3:
+      $_SESSION['category_bulkedit']['step_'. $form_values['step']] = $form_values;
+      break;
+    case 4:
+      // Process the form data from step 4
+      foreach (array(1, 2, 3) as $step_key) {
+        $form_values += $_SESSION['category_bulkedit']['step_'. $step_key];
+      }
+      if (!isset($form_values['parents']) || !is_array($form_values['parents'])) {
+        $form_values['parents'] = array($form_values['parents']);
+      }
+      if (empty($form_values['parents'][0])) {
+        if ($is_cat) {
+          $form_values['parents'][0] = arg(3);
         }
         else {
-          category_bulkedit_set_attribute($element, '#required', FALSE);
+          unset($form_values['parents'][0]);
         }
-        break;
-
-      case 'radio':
-      case 'checkbox':
-        // We can't change these to hidden until right before the next page is rendered, otherwise
-        // the value is lost sometimes.
-        if ($next_page) {
-          category_bulkedit_set_attribute($element, '#type', 'hidden');
-        }
-        break;
-
-      case 'fieldset':
-        if ($next_page) {
-          category_bulkedit_set_attribute($element, '#type', NULL);
-        }
-        break;
-
-      case 'markup':
-        if ($next_page) {
-          if (is_array($element['#parents'])) {
-            if (!isset($element['#name'])) {
-              category_bulkedit_set_attribute($element, '#name', 'edit[' . implode('][', $element['#parents']) . ']');
-            }
-            if (!isset($element['#id'])) {
-              category_bulkedit_set_attribute($element, '#id', 'edit-' . implode('-', $element['#parents']));
-            }
-          }
-          category_bulkedit_set_attribute($element, '#type', 'value');
-        }
-        break;
-
-      case 'button':
-        if ($next_page) {
-          category_bulkedit_set_attribute($element, '#type', 'value');
-        }
-        break;
-
-      case 'submit':
-        if ($next_page) {
-          category_bulkedit_set_attribute($element, '#type', 'button');
-        }
-        break;
-    }
-  }
-  else {
-    if ((in_array($element['#type'], array('select', 'activeselect')) && $element['#multiple']) || $element['#type'] == 'radios') {
-      if ($element['#category_bulkedit_original_#required'] && $next_page) {
-        category_bulkedit_set_attribute($element, '#required', $element['#category_bulkedit_original_#required']);
       }
-      if ($element['#default_value'] && empty($element['#value']) && $next_page) {
-        category_bulkedit_set_attribute($element, '#value', $element['#default_value']);
+      if (!isset($form_values['nodes']) || !is_array($form_values['nodes'])) {
+        $form_values['nodes'] = array($form_values['nodes']);
+      }
+      if (empty($form_values['nodes'][0])) {
+        unset($form_values['nodes'][0]);
       }
-    }
-  }
-
-  foreach (element_children($element) as $key) {
-    category_bulkedit_set_element_visibility($element[$key], $visible, $next_page);
-  }
-}
-
-/**
- * Set an attribute on an element array with storing the previous value which
- * may be reverted to using category_bulkedit_restore_attributes().
- *
- * @param $element
- *   The form element array to modify.
- * @param $key
- *   A key of the form element array.
- * @param $new_value
- *   The new value for the attribute.
- */
-function category_bulkedit_set_attribute(&$element, $key, $new_value) {
-  $element['#category_bulkedit_original_'. $key] = $element[$key];
-  $element[$key] = $new_value;
-}
-
-/**
- * Restore any form attributes which have been set using
- * category_bulkedit_set_attribute().
- *
- * @param $element
- *   The form element array to restore.
- */
-function category_bulkedit_restore_attributes(&$element) {
-  foreach (array_filter(array_keys($element), create_function('$key', 'return (strpos($key, "#category_bulkedit_original_") === 0);')) as $key) {
-    if ($element['#type'] == 'category_bulkedit_hidden_array') {
-      $element[str_replace('#category_bulkedit_original_', '', $key)] = (isset($element['#options'][$key]) ? $element['#options'][$key] : $key);
-    }
-    else {
-      $element[str_replace('#category_bulkedit_original_', '', $key)] = $element[$value];
-    }
-  }
-}
-
-/**
- * Playing around here with a new form element to enable storing hidden values in an array fashion.
- * Seems to work fine.  Check out $form['test_hidden_array'] above for how to structure the form
- * element
- */
-function category_bulkedit_elements() {
-   $type['category_bulkedit_hidden_array'] = array('#input' => TRUE, '#process' => array('category_bulkedit_expand_hidden_array' => array()), '#tree' => TRUE);
-   return $type;
-}
-
-function category_bulkedit_expand_hidden_array($element) {
-  $values = is_array($element['#value']) ? $element['#value'] : (!empty($element['#value']) ? array($element['#value']) : array());
-  if ($element['#category_bulkedit_original_#type'] == 'select') {
-    $values = drupal_map_assoc($values);
-  }
-  $element['#tree'] = TRUE;
-
-  foreach (element_children($element) as $key) {
-    unset($element[$key]);
-  }
-
-  foreach ($values as $key) {
-    $element[$key] = array('#type' => 'hidden', '#processed' => TRUE, '#value' => $key);
-
-    if (!isset($element[$key]['#parents'])) {
-      // Check to see if a tree of child elements is present. If so, continue down the tree if required.
-      $element[$key]['#parents'] = $element['#tree'] ? array_merge($element['#parents'], array($key)) : array($key);
-    }
-    $element[$key]['#name'] = 'edit[' . implode('][', $element[$key]['#parents']) . ']';
-    $element[$key]['#id'] =  'edit-' . implode('-', $element[$key]['#parents']);
-  }
-  category_bulkedit_set_attribute($element, '#value', NULL);
 
-  return $element;
-}
+      if (isset($form_values['bulkedit']) && is_array($form_values['bulkedit'])) {
+        $saved_count = 0;
+        foreach ($form_values['bulkedit'] as $nid => $value) {
+          if ($value && is_numeric($nid)) {
+            $node = node_load($nid);
 
-function theme_category_bulkedit_hidden_array($element) {
-  return $element['#children'];
-}
-
-/**
- * Sets the available editing fields for page 3 of the form.
- */
-function _category_bulkedit_set_editing_fields($form = NULL) {
-  static $fields;
+            if (isset($form_values['bulkedit_fields']) && is_array($form_values['bulkedit_fields'])) {
+              foreach ($form_values['bulkedit_fields'] as $field => $field_value) {
+                if ($field_value) {
+                  $node->$field = $form_values[$field];
+                }
+              }
+            }
 
-  if (isset($form)) {
-    $fields = $form;
-  }
+            $node->date = date('j M Y H:i:s', $node->created);
 
-  return $fields;
-}
+            $node = node_submit($node);
 
-function _category_bulkedit_unset_fields($editing_fields, &$form) {
-  if (!empty($editing_fields)) {
-    $edit = $_POST['edit'];
-    foreach (element_children($editing_fields) as $key) {
-      if (($form[$key]['#type'] != 'fieldset') && (!isset($edit['bulkedit_fields'][$key]) || !$edit['bulkedit_fields'][$key])) {
-        unset($form[$key]);
-      }
-      else {
-        if ($form[$key]['#type'] == 'fieldset') {
-          _category_bulkedit_unset_fields($editing_fields[$key], $form[$key]);
+            node_save($node);
+            $saved_count++;
+          }
         }
-      }
-    }
-  }
-}
 
-function _category_bulkedit_set_editing_fields_visibility($editing_fields, &$form, $visible, $next_page = TRUE) {
-  if (!empty($editing_fields)) {
-    foreach (element_children($editing_fields) as $key) {
-      if (isset($form[$key])) {
-        category_bulkedit_set_element_visibility($form[$key], $visible, $next_page);
+        drupal_set_message(t('%count @items were successfully bulk edited.', array('%count' => $saved_count, '@items' => ($is_cat ? t('categories') : t('containers')))));
+        $_SESSION['category_bulkedit'] = NULL;
+
+        drupal_goto('admin/content/category'. ($is_cat ? '/'. arg(3) : ''));
       }
-    }
+      break;
   }
 }
 
@@ -831,15 +643,15 @@ function _category_bulkedit_set_help_tex
 
     switch ($page) {
       case 1:
-        $output = t('<strong>Step 1: %item selection</strong>. Please select the %items that you wish to bulk edit, by ticking the relevant check boxes in the table below.', array('%item' => $item_type, '%items' => $item_type_plural));
+        $output = t('<strong>Step 1: @item selection</strong>. Please select the @items that you wish to bulk edit, by ticking the relevant check boxes in the table below.', array('@item' => $item_type, '@items' => $item_type_plural));
         break;
 
       case 2:
-        $output = t('<strong>Step 2: field selection</strong>. Please select the fields that you wish to bulk edit for your chosen %items, by ticking the relevant check boxes in the table below.', array('%items' => $item_type_plural));
+        $output = t('<strong>Step 2: field selection</strong>. Please select the fields that you wish to bulk edit for your chosen @items, by ticking the relevant check boxes in the table below.', array('@items' => $item_type_plural));
         break;
 
       case 3:
-        $output = t('<strong>Step 3: field selection</strong>. Please select the fields that you wish to bulk edit for your chosen %items, by ticking the relevant check boxes in the table below.', array('%items' => $item_type_plural));
+        $output = t('<strong>Step 3: field editing</strong>. Please edit the selected fields for your chosen @items in the form below.', array('@items' => $item_type_plural));
         break;
 
       case 4:
Index: contrib/category_outliner/category_outliner.info
===================================================================
RCS file: contrib/category_outliner/category_outliner.info
diff -N contrib/category_outliner/category_outliner.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/category_outliner/category_outliner.info	5 Jan 2007 15:20:54 -0000
@@ -0,0 +1,5 @@
+; $Id$
+name = Category outliner
+description = Provides an administrative interface for easily editing and re-arranging categories.
+package = Category
+dependencies = category
Index: contrib/category_outliner/category_outliner.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/category/contrib/category_outliner/category_outliner.module,v
retrieving revision 1.2
diff -u -p -r1.2 category_outliner.module
--- contrib/category_outliner/category_outliner.module	17 May 2006 12:56:31 -0000	1.2
+++ contrib/category_outliner/category_outliner.module	5 Jan 2007 15:20:54 -0000
@@ -12,8 +12,6 @@
  */
 function category_outliner_help($section) {
   switch ($section) {
-    case 'admin/modules#description':
-      return t('Provides an administrative interface for easily editing and re-arranging categories. Requires the category module.');
     case 'admin/category/list/orphan':
       return t('<p>Categories in a site are like a tree. As they are edited, reorganized and removed, children might be left with no link to the rest of the structure.  Such categories are referred to as "orphans".  On this page, administrators can review their site for orphans and reattach those categories as desired.</p>');
   }
@@ -27,40 +25,44 @@ function category_outliner_menu($may_cac
 
   if ($may_cache) {
     $items[] = array(
-      'path' => 'admin/category/list/outline',
-      'title' => t('outline'),
-      'callback' => 'category_outliner_outline',
+      'path' => 'admin/content/category/list/outline',
+      'title' => t('Outline'),
+      'callback' => 'drupal_get_form',
+      'callback arguments' => array('category_outliner_outline'),
       'access' => user_access('administer categories'),
       'type' => MENU_LOCAL_TASK,
       'weight' => -3,
     );
     $items[] = array(
-      'path' => 'admin/category/list/orphan',
-      'title' => t('orphans'),
-      'callback' => 'category_outliner_orphan',
+      'path' => 'admin/content/category/list/orphan',
+      'title' => t('Orphans'),
+      'callback' => 'drupal_get_form',
+      'callback arguments' => array('category_outliner_orphan'),
       'type' => MENU_LOCAL_TASK,
       'access' => user_access('administer categories'),
       'weight' => 0,
     );
   }
   else {
-    if (arg(0) == 'admin' && arg(1) == 'category' && is_numeric(arg(2))) {
-      $nid = arg(2);
+    if (arg(0) == 'admin' && arg(2) == 'category' && is_numeric(arg(3))) {
+      $nid = arg(3);
       $node = node_load($nid);
 
       $items[] = array(
-        'path' => 'admin/category/' . $nid . '/list/outline',
-        'title' => t('outline'),
-        'callback' => 'category_outliner_outline',
+        'path' => 'admin/content/category/' . $nid . '/list/outline',
+        'title' => t('Outline'),
+        'callback' => 'drupal_get_form',
+        'callback arguments' => array('category_outliner_outline'),
         'access' => user_access('administer categories'),
         'type' => MENU_LOCAL_TASK,
         'weight' => -3,
       );
 
       $items[] = array(
-        'path' => 'admin/category/' . $nid . '/list/orphan',
-        'title' => t('orphans'),
-        'callback' => 'category_outliner_orphan',
+        'path' => 'admin/content/category/' . $nid . '/list/orphan',
+        'title' => t('Orphans'),
+        'callback' => 'drupal_get_form',
+        'callback arguments' => array('category_outliner_orphan'),
         'access' => user_access('administer categories'),
         'type' => MENU_LOCAL_TASK,
         'weight' => 0,
@@ -77,11 +79,11 @@ function category_outliner_menu($may_cac
  */
 function category_outliner_outline() {
   $tree = array();
-  if (!is_numeric(arg(2))) {
+  if (!is_numeric(arg(3))) {
     $tree = category_get_tree(0);
   }
   else {
-    $tree = category_get_tree(arg(2));
+    $tree = category_get_tree(arg(3));
   }
 
   if (count($tree) > 0) {
@@ -92,22 +94,22 @@ function category_outliner_outline() {
       '#type' => 'submit',
       '#value' => t('Save categories and containers'),
     );
-
-    return drupal_get_form('category_outliner_outline', $form);
   }
   else {
-    return '<p>'. t('There are no containers or categories.') .'</p>';
+    $form = array('#value' => '<p>'. t('There are no containers or categories.') .'</p>');
   }
+
+  return $form;
 }
 
 /**
  * Menu callback; displays a listing of all orphaned categories.
  */
 function category_outliner_orphan() {
-  $is_cont = is_numeric(arg(2));
+  $is_cont = is_numeric(arg(3));
 
   $container_sql = $is_cont ? 'AND c.cnid = %d' : '';
-  $result = db_query(db_rewrite_sql('SELECT c.*, n.title, c2.cid AS parent_cid FROM {category} c INNER JOIN {node} n ON c.cid = n.nid INNER JOIN {category_hierarchy} ch ON c.cid = ch.cid LEFT JOIN {category} c2 ON ch.parent = c2.cid WHERE ch.parent != 0 '. $container_sql), arg(2));
+  $result = db_query(db_rewrite_sql('SELECT c.*, n.title, c2.cid AS parent_cid FROM {category} c INNER JOIN {node} n ON c.cid = n.nid INNER JOIN {category_hierarchy} ch ON c.cid = ch.cid LEFT JOIN {category} c2 ON ch.parent = c2.cid WHERE ch.parent != 0 '. $container_sql), arg(3));
 
   $categories = array();
   $non_orphans = array();
@@ -141,12 +143,12 @@ function category_outliner_orphan() {
       '#type' => 'submit',
       '#value' => t('Save categories and containers'),
     );
-
-    return drupal_get_form('category_outliner_outline', $form);
   }
   else {
-    return '<p>'. t('There are no orphan categories or containers.') .'</p>';
+    $form = array('#value' => '<p>'. t('There are no containers or categories.') .'</p>');
   }
+
+  return $form;
 }
 
 function category_outliner_outline_submit($form_id, $form_values) {
@@ -158,11 +160,11 @@ function category_outliner_outline_submi
       $node->weight = $row['weight'];
 
       node_save($node);
-      watchdog('content', t('%type: updated %title.', array('%type' => theme('placeholder', t('category')), '%title' => theme('placeholder', $node->title))), WATCHDOG_NOTICE, l(t('view'), 'node/'. $node->nid));
+      watchdog('content', t('%type: updated %title.', array('%type' => t('category'), '%title' => $node->title)), WATCHDOG_NOTICE, l(t('view'), 'node/'. $node->nid));
     }
   }
 
-  if (arg(3) == 'outline' || arg(4) == 'outline') {
+  if (arg(4) == 'outline' || arg(5) == 'outline') {
     // Updating entire category outline.
     drupal_set_message(t('Updated categories and containers.'));
   }
@@ -190,8 +192,8 @@ function theme_category_outliner_table($
 
     $nid = $form[$key]['nid']['#value'];
     $rows[] = array(
-      '<div style="padding-left: '. (25 * $form[$key]['depth']['#value']) .'px;">'. form_render($form[$key]['title']) .'</div>',
-      form_render($form[$key]['weight']),
+      '<div style="padding-left: '. (25 * $form[$key]['depth']['#value']) .'px;">'. drupal_render($form[$key]['title']) .'</div>',
+      drupal_render($form[$key]['weight']),
       l(t('view'), 'node/'. $nid),
       l(t('edit'), 'node/'. $nid .'/edit', array(), $destination),
       l(t('delete'), 'node/'. $nid .'/delete', array(), $destination)
Index: contrib/category_pathauto/category_pathauto.info
===================================================================
RCS file: contrib/category_pathauto/category_pathauto.info
diff -N contrib/category_pathauto/category_pathauto.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/category_pathauto/category_pathauto.info	5 Jan 2007 15:20:54 -0000
@@ -0,0 +1,5 @@
+; $Id$
+name = Category pathauto
+description = Allows you to generate URL aliases that conform to your site's category structure.
+package = Category
+dependencies = category pathauto
Index: contrib/category_pathauto/category_pathauto.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/category/contrib/category_pathauto/category_pathauto.module,v
retrieving revision 1.1
diff -u -p -r1.1 category_pathauto.module
--- contrib/category_pathauto/category_pathauto.module	1 Jun 2006 11:29:33 -0000	1.1
+++ contrib/category_pathauto/category_pathauto.module	5 Jan 2007 15:20:54 -0000
@@ -12,8 +12,6 @@
  */
 function category_pathauto_help($section) {
   switch ($section) {
-    case 'admin/modules#description':
-      return t('Allows you to generate URL aliases that conform to your site\'s category structure. Requires the category module and the pathauto module.');
     case 'admin/help#category_pathauto':
       return t('<p>The category pathauto module allows you to generate URL aliases that conform to your site\'s category structure.</p><p>This module requires the category module and the pathauto module.</p>');
   }
Index: contrib/category_transform/category_transform.info
===================================================================
RCS file: contrib/category_transform/category_transform.info
diff -N contrib/category_transform/category_transform.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/category_transform/category_transform.info	5 Jan 2007 15:20:54 -0000
@@ -0,0 +1,5 @@
+; $Id$
+name = Category transform
+description = Allows nodes of any type to be transformed into categories or containers.
+package = Category
+dependencies = category
Index: contrib/category_transform/category_transform.install
===================================================================
RCS file: contrib/category_transform/category_transform.install
diff -N contrib/category_transform/category_transform.install
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/category_transform/category_transform.install	5 Jan 2007 15:20:54 -0000
@@ -0,0 +1,49 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Update file for the category_transform module. All functions in this
+ * file are implementations of hook_update_N(), unless indicated otherwise.
+ */
+
+/**
+ * Drupal 5.0 updates
+ */
+function category_transform_update_1() {
+  $ret = array();
+
+  // Update the keys and values of the 'category_transform_node_types_cat' variable.
+  $nodetypes = variable_get('category_transform_node_types_cat', array());
+  foreach ($nodetypes as $nodetype => $val) {
+    if (strpos($nodetype, '-') !== FALSE) {
+      $new_nodetype = str_replace('-', '_', $nodetype);
+      if ($nodetype === $val) {
+        $nodetypes[$new_nodetype] = $new_nodetype;
+      }
+      else {
+        $nodetypes[$new_nodetype] = $val;
+      }
+      unset($nodetypes[$nodetype]);
+    }
+  }
+  variable_set('category_transform_node_types_cat', $nodetypes);
+
+  // Update the keys and values of the 'category_transform_node_types_cont' variable.
+  $nodetypes = variable_get('category_transform_node_types_cont', array());
+  foreach ($nodetypes as $nodetype => $val) {
+    if (strpos($nodetype, '-') !== FALSE) {
+      $new_nodetype = str_replace('-', '_', $nodetype);
+      if ($nodetype === $val) {
+        $nodetypes[$new_nodetype] = $new_nodetype;
+      }
+      else {
+        $nodetypes[$new_nodetype] = $val;
+      }
+      unset($nodetypes[$nodetype]);
+    }
+  }
+  variable_set('category_transform_node_types_cont', $nodetypes);
+
+  return $ret;
+}
Index: contrib/category_transform/category_transform.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/category/contrib/category_transform/category_transform.module,v
retrieving revision 1.4
diff -u -p -r1.4 category_transform.module
--- contrib/category_transform/category_transform.module	17 May 2006 11:32:12 -0000	1.4
+++ contrib/category_transform/category_transform.module	5 Jan 2007 15:20:54 -0000
@@ -7,16 +7,6 @@
  */
 
 /**
- * Implementation of hook_help().
- */
-function category_transform_help($section) {
-  switch ($section) {
-    case 'admin/modules#description':
-      return t('Allows nodes of any type to be transformed into categories or containers. Requires the category module.');
-  }
-}
-
-/**
  * Implementation of hook_perm().
  */
 function category_transform_perm() {
@@ -45,7 +35,7 @@ function category_transform_menu($may_ca
         if (empty($category) || $category->cnid) {
           $items[] = array(
             'path' => "node/$nid/category-cat",
-            'title' => t('category'),
+            'title' => t('Category'),
             'callback' => 'category_transform_outline',
             'callback arguments' => array(arg(1)),
             'access' => _category_transform_privileged('transform categories'),
@@ -58,7 +48,7 @@ function category_transform_menu($may_ca
         if (empty($category) || !$category->cnid) {
           $items[] = array(
             'path' => "node/$nid/category-cont",
-            'title' => t('container'),
+            'title' => t('Container'),
             'callback' => 'category_transform_outline',
             'callback arguments' => array(arg(1)),
             'access' => _category_transform_privileged('transform containers'),
@@ -86,9 +76,9 @@ function category_transform_category($op
         '#collapsible' => TRUE,
         '#collapsed' => TRUE,
       );
-      $options = node_get_types();
-      unset($options['category-cat']);
-      unset($options['category-cont']);
+      $options = node_get_types('names');
+      unset($options['category_cat']);
+      unset($options['category_cont']);
       $form['category_transform']['category_transform_node_types_cat'] = array(
         '#type' => 'checkboxes',
         '#title' => t('Node types that can be transformed into categories'),
@@ -117,14 +107,14 @@ function category_transform_category($op
  * @param $node
  *   The node being outlined.
  * @param $type
- *   The category type the node is being transformed into (either category-cat
- *   or category-cont).
+ *   The category type the node is being transformed into (either category_cat
+ *   or category_cont).
  *
  * @return
- *   The form as rendered by drupal_get_form().
+ *   The form to be rendered by drupal_get_form().
  */
 function category_transform_outline_form($node, $type) {
-  $form = category_get_form(($type == 'category-cat'), $node, FALSE);
+  $form = category_get_form(($type == 'category_cat'), $node, FALSE);
 
   if (category_is_cat_or_cont($node->nid)) {
     $form['update'] = array('#type' => 'submit', '#value' => t('Update category outline'));
@@ -134,8 +124,7 @@ function category_transform_outline_form
     $form['add'] = array('#type' => 'submit', '#value' => t('Add to category outline'));
   }
 
-  drupal_set_title(check_plain($node->title));
-  return drupal_get_form('category_transform_outline', $form);
+  return $form;
 }
 
 /**
@@ -147,13 +136,16 @@ function category_transform_outline($nid
   $node = node_load($nid);
 
   if ($node->nid) {
-    $type = category_node_get_type($node, arg(2));
+    $arg_cat = arg(2) == 'category-cat' ? 'category_cat' : 'category_cont';
+    $type = category_node_get_type($node, $arg_cat);
     $category = category_load($node, $type);
     foreach ($category as $key => $value) {
       $node->$key = $value;
     }
 
-    $output = category_transform_outline_form($node, $type);
+    drupal_set_title(check_plain($node->title));
+
+    $output = drupal_get_form('category_transform_outline_form', $node, $type);
   }
 
   return $output;
@@ -162,7 +154,7 @@ function category_transform_outline($nid
 /**
  * Implementation of hook_form_submit().
  */
-function category_transform_outline_submit($form_id, &$form_values) {
+function category_transform_outline_form_submit($form_id, &$form_values) {
   $op = $_POST['op'];
 
   $node = node_load(arg(1));
@@ -173,7 +165,7 @@ function category_transform_outline_subm
     $form_values['parents'] = array($form_values['parents']);
   }
   if (empty($form_values['parents'][0])) {
-    if ($type == 'category-cat') {
+    if ($type == 'category_cat') {
       $form_values['parents'][0] = $form_values['parent'] = $form_values['cnid'];
     }
     else {
Index: contrib/category_views/category_views.info
===================================================================
RCS file: contrib/category_views/category_views.info
diff -N contrib/category_views/category_views.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/category_views/category_views.info	5 Jan 2007 15:20:54 -0000
@@ -0,0 +1,5 @@
+; $Id$
+name = Category views
+description = Renders node listings on category pages using a view.
+package = Category
+dependencies = category views
Index: contrib/category_views/category_views.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/category/contrib/category_views/category_views.module,v
retrieving revision 1.5
diff -u -p -r1.5 category_views.module
--- contrib/category_views/category_views.module	13 May 2006 14:28:36 -0000	1.5
+++ contrib/category_views/category_views.module	5 Jan 2007 15:20:55 -0000
@@ -11,8 +11,7 @@
  */
 function category_views_help($section) {
   switch ($section) {
-    case 'admin/modules#description':
-      return t('Renders node listings on category pages using a view. Requires the category module and the views module.');
+    case 'admin/help#category_views':
       return t('<p>The category_views module renders node listings on category pages using a view. It requires the category module and the views module to be installed.</p>');
   }
 }
@@ -25,7 +24,7 @@ function category_views_nodeapi(&$node, 
     case 'load':
       if (category_is_cat_or_cont($node->nid)) {
         $type = category_node_get_type($node);
-        $is_cat = $type == 'category-cat';
+        $is_cat = $type == 'category_cat';
         if (!$is_cat) {
           return (array)category_views_cont_load($node->nid);
         }
@@ -55,7 +54,7 @@ function category_views_nodeapi(&$node, 
       }
       elseif (category_is_cat_or_cont($node->nid, TRUE)) {
         $type = category_node_get_type($node);
-        $is_cat = $type == 'category-cat';
+        $is_cat = $type == 'category_cat';
         if (!$is_cat) {
           category_views_cont_update($node);
         }
@@ -63,7 +62,7 @@ function category_views_nodeapi(&$node, 
       break;
     case 'delete':
       $type = category_node_get_type($node);
-      $is_cat = $type == 'category-cat';
+      $is_cat = $type == 'category_cat';
       if (!$is_cat) {
         category_views_cont_delete($node->nid);
       }
@@ -95,7 +94,7 @@ function category_views_category($op, $n
         '#default_value' => isset($node->view_for_cats) ? $node->view_for_cats : 0,
         '#options' => $view_list,
         '#multiple' => FALSE,
-        '#description' => t('The view to use for rendering listings of assigned nodes, in this container and its categories. If you do not check either of the \'show view on\' boxes below, then it makes no difference whether or not you select a view here. Conversely, if you leave this setting at its default value (&lt;none&gt;), then it makes no difference whether or not you check either of the boxes below. If there are no views available, or if the currently available views are not adequate, you can %create-view (<em>warning:</em> clicking this link may cause you to leave this page, and to lose whatever information you have entered so far).', array('%create-view' => l(t('create a new view'), 'admin/views/add'))),
+        '#description' => t('The view to use for rendering listings of assigned nodes, in this container and its categories. If you do not check either of the \'show view on\' boxes below, then it makes no difference whether or not you select a view here. Conversely, if you leave this setting at its default value (&lt;none&gt;), then it makes no difference whether or not you check either of the boxes below. If there are no views available, or if the currently available views are not adequate, you can !create-view (<em>warning:</em> clicking this link may cause you to leave this page, and to lose whatever information you have entered so far).', array('!create-view' => l(t('create a new view'), 'admin/views/add'))),
       );
       $form['category_views']['view_display'] = array(
         '#type' => 'checkboxes',
@@ -229,10 +228,10 @@ function category_views_is_visible($node
   }
 
   if ($node->view_for_cats) {
-    if ($type == 'category-cont' && $node->view_display['cont']) {
+    if ($type == 'category_cont' && $node->view_display['cont']) {
       return TRUE;
     }
-    elseif ($type == 'category-cat' && $node->view_display['cat']) {
+    elseif ($type == 'category_cat' && $node->view_display['cat']) {
       return TRUE;
     }
   }
Index: wrappers/book.info.copyme
===================================================================
RCS file: wrappers/book.info.copyme
diff -N wrappers/book.info.copyme
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ wrappers/book.info.copyme	5 Jan 2007 15:20:55 -0000
@@ -0,0 +1,5 @@
+; $Id$
+name = Book
+description = Wrapper module to provide a compatibility layer between the book module and the category module.
+package = Category
+dependencies = category
Index: wrappers/book.module.copyme
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/category/wrappers/book.module.copyme,v
retrieving revision 1.5
diff -u -p -r1.5 book.module.copyme
--- wrappers/book.module.copyme	31 May 2006 13:24:34 -0000	1.5
+++ wrappers/book.module.copyme	5 Jan 2007 15:20:55 -0000
@@ -70,13 +70,6 @@ function book_submit(&$node) {
 }
 
 /**
- * Implementation of hook_validate().
- */
-function book_validate($node) {
-  node_validate_title($node);
-}
-
-/**
  * Given a node, this function returns an array of 'book node' objects
  * representing the path in the book tree from the root to the
  * parent of the given node.
@@ -242,9 +235,7 @@ function book_category($op, $node = NULL
 function book_help($section) {
   switch ($section) {
     case 'admin/help#book':
-      return t('<p>This is a wrapper module to provide a compatibility layer between the book module and the category module. Modules that depend on the book module should function correctly with this wrapper module enabled, as it routes all book requests to the category API, and converts category data types into book data types. The book module user interface is not available with this wrapper module: you should use the category module user interface instead. For further assistance, see the <a href="%category">category module help page</a>.</p>', array('%category' => url('admin/help', NULL, 'category')));
-    case 'admin/modules#description':
-      return t('Wrapper module to provide a compatibility layer between the book module and the category module. Requires the category module.');
+      return t('<p>This is a wrapper module to provide a compatibility layer between the book module and the category module. Modules that depend on the book module should function correctly with this wrapper module enabled, as it routes all book requests to the category API, and converts category data types into book data types. The book module user interface is not available with this wrapper module: you should use the category module user interface instead. For further assistance, see the <a href="!category">category module help page</a>.</p>', array('!category' => url('admin/help', NULL, 'category')));
   }
 }
 
@@ -254,13 +245,13 @@ function _book_book_into_category(&$node
   while (!$cnid && ($parent_node = node_load($parent))) {
     if (category_is_cat_or_cont($parent_node->nid)) {
       $type = category_node_get_type($parent_node);
-      if ($type == 'category-cont') {
+      if ($type == 'category_cont') {
         $cnid = $parent_node->nid;
       }
     }
   }
   $node->cnid = $cnid;
 
-  $node->type = $cnid ? 'category-cat' : 'category-cont';
+  $node->type = $cnid ? 'category-cat' : 'category_cont';
   $node->parents = $node->parent ? array($node->parent) : array();
 }
Index: wrappers/taxonomy.info.copyme
===================================================================
RCS file: wrappers/taxonomy.info.copyme
diff -N wrappers/taxonomy.info.copyme
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ wrappers/taxonomy.info.copyme	5 Jan 2007 15:20:55 -0000
@@ -0,0 +1,5 @@
+; $Id$
+name = Taxonomy
+description = Wrapper module to provide a compatibility layer between the taxonomy module and the category module.
+package = Category
+dependencies = category
Index: wrappers/taxonomy.module.copyme
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/category/wrappers/taxonomy.module.copyme,v
retrieving revision 1.25
diff -u -p -r1.25 taxonomy.module.copyme
--- wrappers/taxonomy.module.copyme	6 Nov 2006 04:28:14 -0000	1.25
+++ wrappers/taxonomy.module.copyme	5 Jan 2007 15:20:56 -0000
@@ -14,11 +14,15 @@
  * print lists of terms associated with a node. Themes can print taxonomy
  * links with:
  *
- * if (module_exist('taxonomy')) {
+ * if (module_exists('taxonomy')) {
  *   $this->links(taxonomy_link('taxonomy terms', $node));
  * }
  */
 function taxonomy_link($type, $node = NULL) {
+  if (!isset($node) || $type == 'node') {
+    return array();
+  }
+
   if ($type == 'taxonomy terms') {
     $type = 'categories';
     if (isset($node->taxonomy) && is_array($node->taxonomy)) {
@@ -35,11 +39,16 @@ function taxonomy_link($type, $node = NU
       }
     }
   }
-  elseif ($type == 'node') {
-    return array();
+
+  $links = category_link($type, $node);
+
+  // We call this hook again because some modules and themes call taxonomy_link('taxonomy terms') directly
+  foreach (module_implements('link_alter') as $module) {
+    $function = $module .'_link_alter';
+    $function($node, $links);
   }
 
-  return category_link($type, $node);
+  return $links;
 }
 
 /**
@@ -49,7 +58,7 @@ function taxonomy_menu($may_cache) {
   $items = array();
 
   if ($may_cache) {
-    if (!module_exist('category_legacy')) {
+    if (!module_exists('category_legacy')) {
       $items[] = array('path' => 'taxonomy/term', 'title' => t('taxonomy term'),
         'callback' => 'taxonomy_term_page',
         'access' => user_access('access content'),
@@ -132,7 +141,7 @@ function taxonomy_save_vocabulary(&$edit
   if (!$only_legacy) {
     $node->title = $edit['name'];
     $node->nid = $edit['vid'];
-    $node->type = 'category-cont';
+    $node->type = 'category_cont';
     $node->description = $edit['description'];
     $node->help = $edit['help'] ? $edit['help'] : '';
     $node->multiple = $edit['multiple'];
@@ -146,7 +155,6 @@ function taxonomy_save_vocabulary(&$edit
     // Force defaults
     $node_options = variable_get('node_options_'. $node->type, array('status', 'promote'));
     $node->status = in_array('status', $node_options);
-    $node->moderate = in_array('moderate', $node_options);
     $node->promote = in_array('promote', $node_options);
     $node->sticky = in_array('sticky', $node_options);
     $node->revision = in_array('revision', $node_options);
@@ -273,7 +281,6 @@ function taxonomy_save_term(&$edit, $onl
     // Force defaults
     $node_options = variable_get('node_options_'. $node->type, array('status', 'promote'));
     $node->status = in_array('status', $node_options);
-    $node->moderate = in_array('moderate', $node_options);
     $node->promote = in_array('promote', $node_options);
     $node->sticky = in_array('sticky', $node_options);
     $node->revision = in_array('revision', $node_options);
@@ -590,6 +597,20 @@ function taxonomy_node_delete($nid) {
 }
 
 /**
+ * Implementation of hook_node_type().
+ */
+function taxonomy_node_type($op, $info) {
+  if (variable_get('taxonomy_maintain_db', 1)) {
+    if ($op == 'update' && !empty($info->old_type) && $info->type != $info->old_type) {
+      db_query("UPDATE {vocabulary_node_types} SET type = '%s' WHERE type = '%s'", $info->type, $info->old_type);
+    }
+    elseif ($op == 'delete') {
+      db_query("DELETE FROM {vocabulary_node_types} WHERE type = '%s'", $info->type);
+    }
+  }
+}
+
+/**
  * Find all term objects related to a given term ID.
  */
 function taxonomy_get_related($tid, $key = 'tid') {
@@ -778,10 +799,6 @@ function taxonomy_get_term($tid) {
   return _taxonomy_category_into_term($category);
 }
 
-function _taxonomy_depth($depth, $graphic = '--') {
-  return _category_depth($depth, $graphic);
-}
-
 /**
  * Finds all nodes that match selected taxonomy conditions.
  *
@@ -823,7 +840,7 @@ function taxonomy_nodeapi(&$node, $op, $
     case 'insert':
       if (category_is_cat_or_cont($node->nid)) {
         $type = category_node_get_type($node);
-        $is_cat = $type == 'category-cat';
+        $is_cat = $type == 'category_cat';
         if ($is_cat) {
           taxonomy_save_term($edit = _taxonomy_prepare_edit_term($node), TRUE, $node->nid);
         }
@@ -831,12 +848,15 @@ function taxonomy_nodeapi(&$node, $op, $
           taxonomy_save_vocabulary($edit = _taxonomy_prepare_edit_vocabulary($node), TRUE, $node->nid);
         }
       }
+      if (empty($node->taxonomy)) {
+        $node->taxonomy = taxonomy_node_get_terms($node->nid);
+      }
       taxonomy_node_save($node->nid, $node->taxonomy, $node);
       break;
     case 'update':
       if (category_is_cat_or_cont($node->nid)) {
         $type = category_node_get_type($node);
-        $is_cat = $type == 'category-cat';
+        $is_cat = $type == 'category_cat';
         if ($is_cat) {
           taxonomy_save_term($edit = _taxonomy_prepare_edit_term($node, TRUE), TRUE);
         }
@@ -844,12 +864,15 @@ function taxonomy_nodeapi(&$node, $op, $
           taxonomy_save_vocabulary($edit = _taxonomy_prepare_edit_vocabulary($node, TRUE), TRUE);
         }
       }
+      if (empty($node->taxonomy)) {
+        $node->taxonomy = taxonomy_node_get_terms($node->nid);
+      }
       taxonomy_node_save($node->nid, $node->taxonomy, $node);
       break;
     case 'delete':
       if (category_is_cat_or_cont($node->nid)) {
         $type = category_node_get_type($node);
-        $is_cat = $type == 'category-cat';
+        $is_cat = $type == 'category_cat';
         if ($is_cat) {
           taxonomy_del_term($node->nid);
         }
@@ -862,6 +885,14 @@ function taxonomy_nodeapi(&$node, $op, $
   }
 }
 
+function taxonomy_terms_parse_string($str_tids) {
+  $terms = category_categories_parse_string($str_tids);
+  $terms['tids'] = $terms['cids'];
+  unset($terms['cids']);
+
+  return $terms;
+}
+
 /**
  * Place assigned categories in the form as taxonomy terms.
  */
@@ -891,9 +922,7 @@ function taxonomy_rss_item($node) {
 function taxonomy_help($section) {
   switch ($section) {
     case 'admin/help#taxonomy':
-      return t('<p>This is a wrapper module to provide a compatibility layer between the taxonomy module and the category module. Modules that depend on the taxonomy module should function correctly with this wrapper module enabled, as it routes all taxonomy requests to the category API, and converts category data types into taxonomy data types. The taxonomy module user interface is not available with this wrapper module: you should use the category module user interface instead. For further assistance, see the <a href="%category">category module help page</a>.</p>', array('%category' => url('admin/help', NULL, 'category')));
-    case 'admin/modules#description':
-      return t('Wrapper module to provide a compatibility layer between the taxonomy module and the category module. Requires the category module.');
+      return t('<p>This is a wrapper module to provide a compatibility layer between the taxonomy module and the category module. Modules that depend on the taxonomy module should function correctly with this wrapper module enabled, as it routes all taxonomy requests to the category API, and converts category data types into taxonomy data types. The taxonomy module user interface is not available with this wrapper module: you should use the category module user interface instead. For further assistance, see the <a href="!category">category module help page</a>.</p>', array('!category' => url('admin/help', NULL, 'category')));
   }
 }
 
@@ -935,7 +964,7 @@ function _taxonomy_confirm_del_term($tid
   $form['tid'] = array('#type' => 'hidden', '#value' => $tid);
   return confirm_form('term_confirm_delete', $form,
                   t('Are you sure you want to delete the term %title?',
-                  array('%title' => theme('placeholder', $term->name))),
+                  array('%title' => $term->name)),
                   'admin/category',
                   t('This action cannot be undone.'),
                   t('Delete'),
