You are here

taxonomy_manager.module in Taxonomy Manager 5

Taxonomy Manager

Administration interface for managing taxonomy vocabularies

File

taxonomy_manager.module
View source
<?php

/**
 * 
 * @file
 * Taxonomy Manager
 * 
 * Administration interface for managing taxonomy vocabularies
 * 
 */

/**
 * Implementation of hook_menu
 */
function taxonomy_manager_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'path' => 'admin/content/taxonomy_manager',
      'title' => t('Taxonomy Manager'),
      'description' => t('Administer vocabularies with the Taxonomy Manager'),
      'callback' => 'taxonomy_manager_voc_list',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_NORMAL_ITEM,
    );
    $items[] = array(
      'path' => 'admin/content/taxonomy_manager/childform',
      'callback' => 'taxonomy_manager_tree_build_child_form',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/content/taxonomy_manager/weight',
      'callback' => 'taxonomy_manager_update_weights',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/content/taxonomy_manager/termdata',
      'callback' => 'taxonomy_manager_update_term_data_form',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/content/taxonomy_manager/siblingsform',
      'callback' => 'taxonomy_manager_tree_build_siblings_form',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/content/taxonomy_manager/termdata/edit',
      'callback' => 'taxonomy_manager_term_data_edit',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/content/taxonomy_manager/export',
      'callback' => 'taxonomy_manager_export',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'admin/settings/taxonomy_manager',
      'title' => t('Taxonomy Manager'),
      'description' => t('Advanced settings for the Taxonomy Manager'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'taxonomy_manager_settings',
      ),
      'access' => user_access('administer site configuration'),
    );

    //override default term page so that we can consider merged terms
    $items[] = array(
      'path' => 'taxonomy/term',
      'title' => t('Taxonomy term'),
      'callback' => 'taxonomy_manager_term_page',
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK,
    );
  }
  else {
    if (arg(0) == 'admin' && arg(1) == 'content' && arg(2) == 'taxonomy_manager' && is_numeric(arg(3))) {
      $vid = arg(3);
      $items[] = array(
        'path' => 'admin/content/taxonomy_manager/' . $vid,
        'title' => t('Taxonomy Manager'),
        'callback' => 'taxonomy_manager_voc',
        'callback arguments' => array(
          $vid,
        ),
        'access' => user_access('administer taxonomy'),
        'type' => MENU_CALLBACK,
      );
    }
  }
  return $items;
}

/**
 * Implementation of hook_help().
 */
function taxonomy_manager_help($section) {
  switch ($section) {
    case 'admin/help#taxonomy_manager':
      $output = t('The Taxonomy Manager provides an additional interface for managing vocabularies of the taxonomy module. It\'s especially very useful for long sets of terms.
                   The vocabulary is represented in a dynamic tree view.
                   It supports operation like mass adding and deleting of terms, fast weight editing, moving of terms in hierarchies, merging of terms and fast term data editing.
                   For more information on how to use please read the readme file included in the taxonomy_manager directory.');
      return $output;
  }
}

/**
 * list of vocabularies, which link to Taxonomy Manager interface
 */
function taxonomy_manager_voc_list() {
  $vocabularies = taxonomy_get_vocabularies();
  $voc_list = array();
  foreach ($vocabularies as $vocabulary) {
    $voc_list[] = l($vocabulary->name, 'admin/content/taxonomy_manager/' . $vocabulary->vid);
  }
  return theme('item_list', $voc_list, t("Vocabularies:"));
}

/**
 * returns either form for deletion confirm or the taxonomy manager form
 */
function taxonomy_manager_voc($vid, $tid = 0, $filter = NULL) {
  if ($_POST['op'] == t('Delete') || $_POST['confirm']) {
    return drupal_get_form('taxonomy_manager_terms_confirm_delete', $vid, $_POST);
  }
  return drupal_get_form('taxonomy_manager_form', $vid, $tid, $filter);
}

/**
 * defines forms for taxonomy manager interface
 * 
 * @param $vid vocabulary id
 * @param $tid a term id, if not 0, displays term editing from for given tid on right side
 * @param $search_string a string to filter root level terms
 */
function taxonomy_manager_form($vid, $tid = 0, $filter = NULL) {
  $module_path = drupal_get_path('module', 'taxonomy_manager') . '/';
  drupal_add_css($module_path . 'css/taxonomy_manager.css');
  drupal_add_js($module_path . 'js/hideForm.js');
  drupal_add_js($module_path . 'js/updateWeight.js');
  drupal_add_js($module_path . 'js/termData.js');
  drupal_add_js('misc/textarea.js');

  //because of term data form wich gets dynamically loaded
  drupal_add_js(array(
    'termData' => array(
      'url' => url("admin/content/taxonomy_manager/termdata/edit/" . $vid),
      'tid' => $tid,
      'term_url' => url(taxonomy_manager_tree_link($vid) . '/' . $tid . '/true'),
    ),
  ), 'setting');
  drupal_add_js(array(
    'updateWeight' => array(
      'up' => 'edit-weight-up',
      'down' => 'edit-weight-down',
      'url' => url('admin/content/taxonomy_manager/weight/' . $vid),
      'disable_mouseover' => variable_get('taxonomy_manager_disable_mouseover_weights', 0),
    ),
  ), 'setting');
  $form = array();
  $voc = taxonomy_get_vocabulary($vid);
  drupal_set_title(t("Taxonomy Manager - %voc_name", array(
    "%voc_name" => $voc->name,
  )));
  if (!is_numeric($voc->vid)) {
    $text = t('No vocabulary with this ID available!. ');
    $text .= t('Check this !link_list for available vocabularies or !link_create a new one', array(
      '!link_list' => l('list', 'admin/content/taxonomy_manager'),
      '!link_create' => l('create', 'admin/content/taxonomy/add/vocabulary'),
    ));
    $form['text'] = array(
      '#value' => $text,
    );
    return $form;
  }
  $form['vid'] = array(
    '#type' => 'value',
    "#value" => $vid,
  );
  if (_taxonomy_manager_voc_is_empty($vid)) {
    $text = t('No terms available');
    $form['text'] = array(
      '#value' => $text,
    );
    $form += taxonomy_manager_add_form($voc, false);
    return $form;
  }
  $form['taxonomy']['#tree'] = TRUE;
  $form['taxonomy']['manager'] = array(
    '#type' => 'fieldset',
    '#title' => check_plain($voc->name),
    '#weight' => 10,
    '#tree' => TRUE,
    '#prefix' => '<div id="taxonomy-manager-tree-outer-div">',
    '#suffix' => '</div>',
  );
  $form['taxonomy']['manager']['tree'] = array(
    '#type' => 'taxonomy_manager_tree',
    '#vid' => $vid,
    '#pager' => TRUE,
    '#search_string' => $tid ? NULL : $filter,
  );
  $search_description = t("You can search directly for exisiting terms. \n      If your input doesn't match an existing term, it will be used for filtering root level terms (useful for non-hierarchical vocabularies).");
  $form['search'] = array(
    '#type' => 'fieldset',
    '#attributes' => array(
      'id' => 'taxonomy-manager-search',
    ),
    '#title' => t('Search'),
    '#description' => $search_description,
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
    '#tree' => TRUE,
  );
  $form['search']['field'] = array(
    '#type' => 'textfield',
    '#title' => t('Search String'),
    '#autocomplete_path' => 'taxonomy/autocomplete/' . $voc->vid,
    '#prefix' => '<div id="edit-find-field">',
    '#suffix' => '</div>',
  );
  $form['search']['button'] = array(
    '#type' => 'submit',
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons search',
    ),
    '#value' => t('Search'),
    '#suffix' => '<div class="clear"></div>',
  );
  $form['toolbar'] = array(
    '#type' => 'fieldset',
    '#title' => t('Toolbar'),
    '#attributes' => array(
      'id' => 'taxonomy-manager-toolbar',
    ),
  );
  $form['toolbar']['weight_up'] = array(
    '#type' => 'button',
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons',
    ),
    '#value' => t('Up'),
    '#theme' => 'no_submit_button',
    '#prefix' => '<div id="taxonomy-manager-toolbar-buttons">',
  );
  $form['toolbar']['weight-down'] = array(
    '#type' => 'button',
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons',
    ),
    '#value' => t('Down'),
    '#theme' => 'no_submit_button',
  );
  $form['toolbar']['delete_confirm'] = array(
    '#type' => 'button',
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons delete',
    ),
    '#value' => t('Delete'),
    '#theme' => 'no_submit_button',
  );
  $form['toolbar']['add_show'] = array(
    '#type' => 'button',
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons add',
    ),
    '#value' => t('Add'),
    '#theme' => 'no_submit_button',
  );

  //moving is only possible in hierarchies...
  if ($voc->hierarchy != 0) {
    $form['toolbar']['move_show'] = array(
      '#type' => 'button',
      '#value' => t('Move'),
      '#attributes' => array(
        'class' => 'taxonomy-manager-buttons move',
      ),
      '#theme' => 'no_submit_button',
    );
  }
  $form['toolbar']['merge_show'] = array(
    '#type' => 'button',
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons merge',
    ),
    '#value' => t('Merge'),
    '#theme' => 'no_submit_button',
  );
  $form['toolbar']['export_show'] = array(
    '#type' => 'button',
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons export',
    ),
    '#value' => t('CSV Export'),
    '#theme' => 'no_submit_button',
    '#suffix' => '</div>',
  );
  $form['toolbar']['wrapper'] = array(
    '#type' => 'markup',
    '#value' => '<div id="taxonomy-manager-toolbar-throbber"></div><div class="clear"></div>',
    '#weight' => 20,
  );
  $form += taxonomy_manager_add_form($voc);
  $form += taxonomy_manager_merge_form($voc);
  $form += taxonomy_manager_move_form($voc);
  $form += taxonomy_manager_confirm_delete($voc);
  $form += taxonomy_manager_export_form($voc);
  if ($tid) {
    $form += taxonomy_manager_form_term_data($tid);
  }
  return $form;
}

/**
 * function gets called by the taxonomy_manager_tree form type (form_id +_operations)
 * return an form array with values to show next to every term value
 */
function taxonomy_manager_tree_operations() {
  $form = array();
  if (!variable_get('taxonomy_manager_disable_mouseover_weights', 0)) {
    $module_path = drupal_get_path('module', 'taxonomy_manager') . '/';
    $form['up'] = array(
      '#value' => theme("image", $module_path . "images/go-up-small.png", "go up", NULL, array(
        'class' => 'term-up',
      )),
    );
    $form['down'] = array(
      '#value' => theme("image", $module_path . "images/go-down-small.png", "go down", NULL, array(
        'class' => 'term-down',
      )),
    );
  }
  return $form;
}

/**
 * function gets called by taxonomy_manager_tree form type (form_id +_link)
 * and returns an link, where to go, when a term gets clicked
 *
 * @param $vid vocabulary id
 */
function taxonomy_manager_tree_link($vid) {
  return "admin/content/taxonomy_manager/termdata/" . $vid;
}

/**
 * confirmation form for deleting selected terms
 */
function taxonomy_manager_confirm_delete($voc) {
  drupal_add_js(array(
    'hideForm' => array(
      'show_button' => 'edit-delete-confirm',
      'hide_button' => 'edit-delete-cancel',
      'div' => 'del-confirm-form',
    ),
  ), 'setting');
  $form = array();
  $form['delete'] = array(
    '#type' => 'fieldset',
    '#tree' => TRUE,
    '#title' => t('Confirmation'),
    '#prefix' => '<div id="del-confirm-form">',
    '#suffix' => '</div>',
  );
  $question = t('Are you sure you want to delete all selected terms? ');
  $info = t('Remember all term specific data will be lost. This action cannot be undone.');
  $form['delete']['text'] = array(
    '#value' => "<b>" . $question . "</b><br/>" . $info,
  );
  if ($voc->hierarchy != 0) {
    $options = array(
      'delete_orphans' => t('Delete children of selected terms, if there are any'),
    );
    $form['delete']['options'] = array(
      '#type' => 'checkboxes',
      '#title' => t('Options'),
      '#options' => $options,
    );
  }
  $form['delete']['delete'] = array(
    '#type' => 'submit',
    '#value' => t('Delete'),
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons delete',
    ),
  );
  $form['delete']['cancel'] = array(
    '#type' => 'button',
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons cancel',
    ),
    '#value' => t('Cancel'),
    '#theme' => 'no_submit_button',
  );
  return $form;
}

/**
 * form for adding terms
 */
function taxonomy_manager_add_form($voc, $hide_form = TRUE) {
  if ($hide_form) {
    drupal_add_js(array(
      'hideForm' => array(
        'show_button' => 'edit-add-show',
        'hide_button' => 'edit-add-cancel',
        'div' => 'add-form',
      ),
    ), 'setting');
  }
  $form = array();
  $description = "";
  if ($voc->hierarchy >= 1) {
    $description = t("If you have selected one or more terms in the tree view, the new terms are automatically children of those.");
  }
  $form['add'] = array(
    '#type' => 'fieldset',
    '#tree' => TRUE,
    '#title' => t('Add new terms'),
    '#prefix' => '<div id="add-form">',
    '#suffix' => '</div>',
    '#description' => $description,
  );
  for ($i = 0; $i < 6; $i++) {
    $form['add']['term'][$i] = array(
      '#type' => 'textfield',
    );
  }
  $form['add']['mass'] = array(
    '#type' => 'fieldset',
    '#tree' => TRUE,
    '#title' => t('Mass term import (with textarea)'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $form['add']['mass']['mass_add'] = array(
    '#type' => 'textarea',
    '#title' => t('Terms'),
    '#description' => t('One term per line'),
    '#rows' => 10,
  );
  $form['add']['add'] = array(
    '#type' => 'submit',
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons add',
    ),
    '#value' => t('Add'),
  );
  $form['add']['cancel'] = array(
    '#type' => 'button',
    '#value' => t('Cancel'),
    '#theme' => 'no_submit_button',
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons cancel',
    ),
  );
  return $form;
}

/**
 * form for merging terms
 */
function taxonomy_manager_merge_form($voc) {
  drupal_add_js(array(
    'hideForm' => array(
      'show_button' => 'edit-merge-show',
      'hide_button' => 'edit-merge-cancel',
      'div' => 'merge-form',
    ),
  ), 'setting');
  $form = array();
  $description .= t("The selected terms get merged into one term. \n    This resulting merged term can either be an exisiting term or a completely new term. \n    The selected terms will automatically get synomyms of the merged term and will be deleted afterwards.");
  $form['merge'] = array(
    '#type' => 'fieldset',
    '#tree' => TRUE,
    '#title' => t('Merging of terms'),
    '#description' => $description,
    '#prefix' => '<div id="merge-form">',
    '#suffix' => '</div>',
  );
  $form['merge']['main_term'] = array(
    '#type' => 'textfield',
    '#title' => t('Resulting merged term'),
    '#required' => FALSE,
    '#autocomplete_path' => 'taxonomy/autocomplete/' . $voc->vid,
  );
  $options = array();
  switch ($voc->hierarchy) {

    //multiple hierarchy
    case 2:
      $options['collect_parents'] = t('Collect all parents of selected terms an add it to the merged term');

    //single hierarchy
    case 1:
      $options['collect_children'] = t('Collect all children of selected terms an add it to the merged term');
      break;
  }
  if ($voc->relations) {
    $options['collect_relations'] = t('Collect all relations of selected terms an add it to the merged term');
  }
  if (count($options) > 0) {
    $form['merge']['options'] = array(
      '#type' => 'checkboxes',
      '#title' => t('Options'),
      '#options' => $options,
    );
  }
  $form['merge']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Merge'),
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons merge',
    ),
  );
  $form['merge']['cancel'] = array(
    '#type' => 'button',
    '#value' => t('Cancel'),
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons cancel',
    ),
    '#theme' => 'no_submit_button',
  );
  return $form;
}

/**
 * form for moving terms in hierarchies
 */
function taxonomy_manager_move_form($voc) {
  drupal_add_js(array(
    'hideForm' => array(
      'show_button' => 'edit-move-show',
      'hide_button' => 'edit-move-cancel',
      'div' => 'move-form',
    ),
  ), 'setting');
  $form = array();
  $description = t("You can change the parent of one or more selected terms. \n      If you leave the autocomplete field empty, the term will be a root term.");
  $form['move'] = array(
    '#type' => 'fieldset',
    '#tree' => TRUE,
    '#title' => t('Moving of terms'),
    '#description' => $description,
    '#prefix' => '<div id="move-form">',
    '#suffix' => '</div>',
  );
  if ($voc->hierarchy == 2) {
    $auto_description .= t("Separate parent terms with a comma. ");
  }
  $form['move']['parents'] = array(
    '#type' => 'textfield',
    '#title' => t('Parent term(s)'),
    '#description' => $auto_description,
    '#required' => FALSE,
    '#autocomplete_path' => 'taxonomy/autocomplete/' . $voc->vid,
  );
  $options = array();
  if ($voc->hierarchy == 2) {
    $options['keep_old_parents'] = t('Keep old parents and add new ones (multi-parent). Otherwise old parents get replaced.');
  }
  if (count($options) > 0) {
    $form['move']['options'] = array(
      '#type' => 'checkboxes',
      '#title' => t('Options'),
      '#options' => $options,
    );
  }
  $form['move']['submit'] = array(
    '#type' => 'submit',
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons move',
    ),
    '#value' => t('Move'),
  );
  $form['move']['cancel'] = array(
    '#type' => 'button',
    '#value' => t('Cancel'),
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons cancel',
    ),
    '#theme' => 'no_submit_button',
  );
  return $form;
}

/**
 * form for exporting terms
 */
function taxonomy_manager_export_form($voc) {
  drupal_add_js(array(
    'hideForm' => array(
      'show_button' => 'edit-export-show',
      'hide_button' => 'edit-export-cancel',
      'div' => 'export-form',
    ),
  ), 'setting');
  $module_path = drupal_get_path('module', 'taxonomy_manager') . '/';
  drupal_add_js($module_path . 'js/csv_export.js');
  drupal_add_js(array(
    'exportCSV' => array(
      'url' => url("admin/content/taxonomy_manager/export"),
    ),
  ), 'setting');
  $form = array();
  $form['export'] = array(
    '#type' => 'fieldset',
    '#tree' => TRUE,
    '#title' => t('CSV Export'),
    '#description' => $description,
    '#prefix' => '<div id="export-form">',
    '#suffix' => '</div>',
  );
  $form['export']['delimiter'] = array(
    '#type' => 'textfield',
    '#title' => t('Delimiter for CSV File'),
    '#required' => FALSE,
    '#default_value' => ";",
  );
  $options['whole_voc'] = t('Whole Vocabulary');
  $options['children'] = t('Child terms of a selected term');
  $options['root_terms'] = t('Root level terms only');
  $form['export']['options'] = array(
    '#type' => 'radios',
    '#title' => t('Terms to export'),
    '#options' => $options,
    '#default_value' => 'whole_voc',
    '#prefix' => '<div id="taxonomy_manager_export_options">',
    '#suffix' => '</div>',
  );
  $form['export']['csv'] = array(
    '#type' => 'textarea',
    '#title' => t('Exported CSV'),
    '#description' => t('The generated code will appear here (per AJAX). You can copy and paste the code into a .csv file. The csv has following columns: voc id | term id | term name | description | parent id 1 | ... | parent id n'),
    '#rows' => 8,
  );
  $form['export']['submit'] = array(
    '#type' => 'submit',
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons export',
    ),
    '#value' => t('Export now'),
    '#theme' => 'no_submit_button',
  );
  $form['export']['cancel'] = array(
    '#type' => 'button',
    '#value' => t('Cancel'),
    '#attributes' => array(
      'class' => 'taxonomy-manager-buttons cancel',
    ),
    '#theme' => 'no_submit_button',
  );
  return $form;
}

/**
 * menu callback for displaying term data form
 * 
 * if this function gets called by ahah, then the term data form gets 
 * generated, rendered and return
 * otherwise, if no ahah call, redirect to original form with $vid and $tid as parameters
 *
 * @param $vid
 * @param $tid
 * @param $ahah if true, return rendered form, else redirect
 */
function taxonomy_manager_update_term_data_form($vid, $tid, $ahah = FALSE) {
  if (!$ahah) {
    drupal_goto('admin/content/taxonomy_manager/' . $vid . '/' . $tid);
  }
  $GLOBALS['devel_shutdown'] = FALSE;

  //prevent devel queries footprint
  $form = taxonomy_manager_form_term_data($tid);
  $form = form_builder('taxonomy_manager_form', $form);
  $output = drupal_render($form);
  print $output;
  exit;
}

/**
 * term data editing form
 *
 * @param $tid
 */
function taxonomy_manager_form_term_data($tid) {
  $term = taxonomy_get_term($tid);
  $module_path = drupal_get_path('module', 'taxonomy_manager') . '/';
  $vocabulary = taxonomy_get_vocabulary($term->vid);

  //prevent that title of the fieldset is too long
  $title = check_plain($term->name);
  if (strlen($title) >= 33) {
    $title = substr($title, 0, 33) . "...";
  }
  $title .= " (" . $term->tid . ")";
  $form['term_data'] = array(
    '#type' => 'fieldset',
    '#title' => $title,
    '#attributes' => array(
      'id' => 'taxonomy-term-data-fieldset',
    ),
    '#tree' => TRUE,
  );
  $form['term_data']['name'] = array(
    '#type' => 'textfield',
    '#title' => t('Name'),
    '#default_value' => $term->name,
    '#size' => 35,
    '#maxlength' => 255,
    '#required' => TRUE,
    '#weight' => -20,
    '#prefix' => '<div id="term-data-name-field">',
    '#suffix' => '</div>',
  );
  $form['term_data']['save_name'] = array(
    '#value' => theme("image", $module_path . "images/document-save.png", "save", NULL),
    '#prefix' => '<div id="term-data-name-save">',
    '#suffix' => '</div><div class="clear"></div>',
  );
  $form['term_data']['description'] = array(
    '#type' => 'textarea',
    '#title' => t('Description'),
    '#default_value' => $term->description,
    '#cols' => 35,
    '#rows' => 4,
    '#prefix' => '<div id="term-data-description"><div id="term-data-description-field">',
    '#suffix' => '</div>',
  );
  $form['term_data']['save_description'] = array(
    '#value' => theme("image", $module_path . "images/document-save.png", "save", NULL),
    '#prefix' => '<div id="term-data-description-save">',
    '#suffix' => '</div></div><div class="clear"></div>',
  );
  $form['term_data']['synonyms'] = _taxonomy_manager_form_term_data_lists($term, taxonomy_get_synonyms($term->tid), t('Synonyms'), 'synonym', FALSE);
  $form['term_data']['synonyms']['#tree'] = TRUE;
  if ($vocabulary->relations) {
    $form['term_data']['relations'] = _taxonomy_manager_form_term_data_lists($term, taxonomy_get_related($term->tid), t('Relations'), 'related');
    $form['term_data']['relations']['#tree'] = TRUE;
  }
  if ($vocabulary->hierarchy) {
    $parents = taxonomy_get_parents($term->tid);
    $p_add = TRUE;
    if (count($parents) >= 1 && $vocabulary->hierarchy == 1) {
      $p_add = FALSE;
    }
    $form['term_data']['parents'] = _taxonomy_manager_form_term_data_lists($term, $parents, t('Parents'), 'parent', TRUE, $p_add);
    $form['term_data']['parents']['#tree'] = TRUE;
  }
  $form['term_data']['weight'] = array(
    '#type' => 'weight',
    '#default_value' => $term->weight,
    '#delta' => 40,
    '#prefix' => '<div id="term-data-weight">',
    '#suffix' => '</div>',
    '#title' => t('Weight'),
  );
  $form['term_data']['link'] = array(
    '#value' => '<br />' . l(t('Go to the term page site'), taxonomy_term_path($term), array(
      'rel' => 'tag',
      'title' => $term->description,
      'target' => '_blank',
    )),
  );
  return $form;
}

/**
 * helper function for generating tables with values and delete op and field for adding
 *
 * @param $term term object which is going to be displayed
 * @param $values array of values to show, e.g related terms, synonyms, parents, children
 * @param $header_type string to display as header
 * @param $attr attribute type to show, can be 'related', 'synonym', 'parent', 'child'
 * @param $autocomplete if true, adds autocomplete, else a textfield
 * @param $add if true, shows add operation
 * @return an form array
 */
function _taxonomy_manager_form_term_data_lists($term, $values, $header_type, $attr, $autocomplete = TRUE, $add = TRUE) {
  $module_path = drupal_get_path('module', 'taxonomy_manager') . '/';
  $rows = array();
  foreach ($values as $tid => $value) {
    $row = array();
    if (is_object($value)) {
      $name = $value->name;
      $id = $value->tid;
    }
    else {
      $name = $value;
      $id = $value;
    }
    $row[] = array(
      'data' => check_plain($name),
      'class' => 'taxonomy-term-data-name',
      'id' => 'term-' . $id,
    );
    $row[] = array(
      'data' => theme("image", $module_path . "images/list-remove.png", "term-remove", NULL, array(
        'class' => $attr,
      )),
      'class' => 'taxonomy-term-data-operations',
    );
    $rows[] = $row;
  }
  $headers = array(
    t('!type', array(
      '!type' => $header_type,
    )),
    '',
  );
  $form['list'] = array(
    '#value' => theme('table', $headers, $rows, array(
      'class' => 'taxonomy-term-data-table',
    )),
  );
  if ($add) {
    $form['add'] = array(
      '#type' => 'textfield',
      '#prefix' => '<div class="term-data-autocomplete-line"><div class="term-data-autocomplete">',
      '#suffix' => '</div>',
      '#size' => 35,
    );
    if ($autocomplete) {
      $form['add']['#autocomplete_path'] = 'taxonomy/autocomplete/' . $term->vid;
    }
    $form['add_button'] = array(
      '#value' => theme("image", $module_path . "images/list-add.png", "term-remove", NULL, array(
        'class' => $attr,
      )),
      '#prefix' => '<div class="term-data-autocomplete-add">',
      '#suffix' => '</div><div class="clear"></div></div>',
    );
  }
  return $form;
}

/** 
 * Additional confirmation form for deletion
 */
function taxonomy_manager_terms_confirm_delete($vid, $edit) {
  $selected = array();
  if (is_array($edit['taxonomy']['manager']['tree'])) {
    $selected = _taxonomy_manager_tree_get_selected_terms($edit['taxonomy']['manager']['tree']);
  }
  else {
    if (is_array($edit['selected_terms'])) {
      $selected = $edit['selected_terms'];
    }
  }
  $form['selected_terms'] = array(
    '#prefix' => '<ul>',
    '#suffix' => '</ul>',
    '#tree' => TRUE,
  );
  foreach ($selected as $tid) {
    $term = taxonomy_get_term($tid);
    $form['selected_terms'][$tid] = array(
      '#type' => 'hidden',
      '#value' => $tid,
      '#prefix' => '<li>',
      '#suffix' => check_plain($term->name) . "</li>\n",
    );
  }
  if (!count($selected)) {
    return array(
      'info' => array(
        '#value' => t('No terms selected.') . '<br />' . l(t('Back'), 'admin/content/taxonomy_manager/' . $vid),
      ),
    );
  }
  if (isset($edit['delete']['options']['delete_orphans']) || isset($edit['options']['delete_orphans'])) {
    $form['options'] = array(
      '#tree' => TRUE,
    );
    $form['options']['delete_orphans'] = array(
      '#type' => 'hidden',
      '#value' => TRUE,
    );
  }
  $form['vid'] = array(
    '#type' => 'hidden',
    '#value' => $vid,
  );
  $msg = isset($form['options']['delete_orphans']) ? t('Deleting a term will delete all its children if there are any. ') : '';
  $msg .= t('This action cannot be undone.');
  return confirm_form($form, t('Are you sure you want to delete the following terms: '), 'admin/content/taxonomy_manager/' . $vid, $msg, t('Delete terms'), t('Cancel'));
}

/**
 * Submit handler for deletion confirmation form
 */
function taxonomy_manager_terms_confirm_delete_submit($form_id, $form_values) {
  taxonomy_manager_delete_terms($form_values['selected_terms'], $form_values['options']);
  drupal_set_message("Selected terms deleted");
  return 'admin/content/taxonomy_manager/' . $form_values['vid'];
}

/**
 * validates the form
 */
function taxonomy_manager_form_validate($form_id, $form_values) {
  $selected_tids = array();
  $selected_tids = $form_values['taxonomy']['manager']['tree']['selected_terms'];
  switch ($form_values['op']) {
    case t('Add'):

      //check for parents concerning voc settings
      $voc = taxonomy_get_vocabulary($form_values['vid']);
      if ($voc->hierarchy == 0 && count($selected_tids) > 0) {
        form_set_error('add', t('Please unselect terms in the list before adding new terms. This vocabulary doesn\'t provide hierarchies.'));
      }
      else {
        if ($voc->hierarchy == 1 && count($selected_tids) > 1) {
          form_set_error('add', t('Please only select one term in the list (at maximum) as parent. This vocabulary provides only single hirarchies.'));
        }
      }
      break;
    case t('Merge'):
      $main_terms = array();
      $regexp = '%(?:^|,\\ *)("(?>[^"]*)(?>""[^"]* )*"|(?: [^",]*))%x';
      preg_match_all($regexp, $form_values['merge']['main_term'], $matches);
      $main_terms = $matches[1];
      if (!is_array($main_terms) || count($main_terms) == 0 || empty($main_terms[0])) {
        form_set_error('merge][main_term', t("Please enter a name into %title", array(
          '%title' => "'" . t('Main term') . "'",
        )));
      }
      else {
        if (count($main_terms) > 1) {
          form_set_error('merge][main_term', t("Please only enter single names into %title", array(
            '%title' => "'" . t('Main term') . "'",
          )));
        }
      }
      if (count($selected_tids) < 1) {
        form_set_error('merge', t("Please selected terms you want to merge"));
      }
      else {
        if (count($selected_tids) > 50) {
          form_set_error('merge', t("Please select less than 50 terms to merge. Merging to many terms in one step can cause timeouts and inconsistent database states"));
        }
      }
      break;
    case t('Move'):
      if (count($selected_tids) < 1) {
        form_set_error('move', t("Please selected terms you want to move in the hierarchy"));
      }
      break;
  }
}

/**
 * submits the taxonomy manager form
 */
function taxonomy_manager_form_submit($form_id, $form_values) {
  $selected_tids = array();
  $selected_tids = $form_values['taxonomy']['manager']['tree']['selected_terms'];
  switch ($form_values['op']) {
    case t('Search'):
      $search_string = $form_values['search']['field'];
      $terms = array();
      $terms = taxonomy_manager_autocomplete_tags_get_tids($search_string, $form_values['vid'], FALSE);
      $term = array_shift($terms);
      $tid = $term['tid'];
      if ($tid) {
        drupal_goto('admin/content/taxonomy_manager/' . $form_values['vid'] . '/' . $tid);
      }
      else {
        drupal_goto('admin/content/taxonomy_manager/' . $form_values['vid'] . '/0/' . $search_string);
      }
      break;
    case t('Add'):
      $terms = array();
      foreach ($form_values['add']['term'] as $value) {
        if (!empty($value)) {
          $terms[] = $value;
        }
      }
      if ($form_values['add']['mass']['mass_add']) {
        foreach (explode("\n", str_replace("\r", '', $form_values['add']['mass']['mass_add'])) as $term) {
          if ($term) {
            $terms[] = $term;
          }
        }
      }
      foreach ($terms as $name) {
        $term = array();
        $term['name'] = $name;
        $term['vid'] = $form_values['vid'];
        $term['parent'] = $selected_tids;
        taxonomy_save_term($term);
      }
      drupal_set_message("Terms added: " . implode(', ', $terms));
      break;
    case t('Merge'):
      $main_terms = taxonomy_manager_autocomplete_tags_get_tids($form_values['merge']['main_term'], $form_values['vid']);
      $main_term = array_shift($main_terms);
      $new_inserted = false;
      if ($main_term['new']) {
        $new_inserted = true;
      }
      $main_term_tid = $main_term['tid'];
      taxonomy_manager_merge($main_term_tid, $selected_tids, $form_values['merge']['options'], $new_inserted);
      drupal_set_message("Terms merged");
      break;
    case t('Move'):
      $typed_parents = taxonomy_manager_autocomplete_tags_get_tids($form_values['move']['parents'], $form_values['vid']);
      $parents = array();
      foreach ($typed_parents as $parent_info) {
        $parents[] = $parent_info['tid'];
      }
      if (count($parents) == 0) {
        $parents[0] = 0;
      }

      //if empty, delete all parents
      taxonomy_manager_move($parents, $selected_tids, $form_values['move']['options']);
      drupal_set_message("Terms moved");
      break;
    case t('Export now'):
      drupal_set_message('Needs JavaScript enabled');
      break;
  }
  drupal_goto('admin/content/taxonomy_manager/' . $form_values['vid']);
}

/**
 * callback handler for updating term data
 *
 * @param $vid
 */
function taxonomy_manager_term_data_edit($vid) {
  $param = $_POST;
  $tid = $param['tid'];
  $values = $param['value'];
  $attr_type = $param['attr_type'];
  $op = $param['op'];
  $term = taxonomy_get_term($tid);
  if ($term->vid != $vid) {
    return;
  }
  if ($op == 'add') {
    if ($attr_type == 'synonym') {
      $regexp = '%(?:^|,\\ *)("(?>[^"]*)(?>""[^"]* )*"|(?: [^",]*))%x';
      preg_match_all($regexp, $values, $matches);
      $synonyms = array_unique($matches[1]);
      $values = array();
      foreach ($synonyms as $syn) {
        $values[] = trim($syn);
      }
    }
    else {
      $typed_term_tids = array();
      $typed_term_tids = taxonomy_manager_autocomplete_tags_get_tids($values, $term->vid);
      $values = array();
      foreach ($typed_term_tids as $term_info) {
        $values[] = $term_info['tid'];
      }
    }
  }
  switch ($attr_type) {
    case 'name':
      db_query("UPDATE {term_data} SET name = '%s' WHERE tid = %d", $values, $tid);
      break;
    case 'description':
      db_query("UPDATE {term_data} SET description = '%s' WHERE tid = %d", $values, $tid);
      break;
    case 'parent':
      if (!is_array($values)) {
        $values = array(
          $values,
        );
      }
      foreach ($values as $value) {
        db_query("DELETE FROM {term_hierarchy} WHERE parent = %d AND tid = %d", $value, $tid);
        if ($op == 'add') {
          db_query("INSERT INTO {term_hierarchy} (parent, tid) VALUES (%d, %d)", $value, $tid);
        }
      }
      if ($op == 'delete') {
        $parents = taxonomy_get_parents($tid);
        if (count($parents) == 0) {

          //ensure that a term has a least parent 0
          db_query("DELETE FROM {term_hierarchy} WHERE parent = 0 AND tid = %d", $tid);
          db_query("INSERT INTO {term_hierarchy} (parent, tid) VALUES (0, %d)", $tid);
        }
      }
      else {
        if ($op == 'add') {
          db_query("DELETE FROM {term_hierarchy} WHERE parent = 0 AND tid = %d", $tid);
        }
      }
      break;
    case 'related':
      if (!is_array($values)) {
        $values = array(
          $values,
        );
      }
      foreach ($values as $value) {
        if ($value != 0) {
          db_query("DELETE FROM {term_relation} WHERE tid1 = %d AND tid2 = %d", $tid, $value);
          db_query("DELETE FROM {term_relation} WHERE tid2 = %d AND tid1 = %d", $tid, $value);
          if ($op == 'add') {
            db_query('INSERT INTO {term_relation} (tid1, tid2) VALUES (%d, %d)', $tid, $value);
          }
        }
      }
      break;
    case 'synonym':
      if (!is_array($values)) {
        $values = array(
          $values,
        );
      }
      foreach ($values as $value) {
        db_query("DELETE FROM {term_synonym} WHERE tid = %d AND name = '%s'", $tid, $value);
        if ($op == 'add') {
          db_query("INSERT INTO {term_synonym} (tid, name) VALUES (%d, '%s')", $tid, $value);
        }
      }
      break;
    case 'weight':
      if (is_numeric($values)) {
        db_query("UPDATE {term_data} SET weight = %d WHERE tid = %d", $values, $tid);
      }
      break;
  }
  module_invoke_all('taxonomy', 'update', 'term', (array) taxonomy_get_term($tid));
  exit;
}

/**
 * Defines a settings form.
 */
function taxonomy_manager_settings() {
  $form['taxonomy_manager_disable_mouseover_weights'] = array(
    '#type' => 'checkbox',
    '#title' => t('Disable mouse-over effect for weight arrows'),
    '#default_value' => variable_get('taxonomy_manager_disable_mouseover_weights', 0),
    '#description' => t('Disabeling this feature speeds up the Taxonomy Manager'),
  );
  $form['taxonomy_manager_pager_tree_page_size'] = array(
    '#type' => 'select',
    '#title' => t('Select how many terms get listet on one page (pager count)'),
    '#options' => array(
      25 => 25,
      50 => 50,
      75 => 75,
      100 => 100,
      150 => 150,
      200 => 200,
      250 => 250,
      300 => 300,
      400 => 400,
      500 => 500,
    ),
    '#default_value' => variable_get('taxonomy_manager_pager_tree_page_size', 50),
    '#description' => t('Huge page counts can slow down the Taxonomy Manager'),
  );
  return system_settings_form($form);
}

/**
 * checks if voc has terms
 *
 * @param $vid voc id
 * @return true, if terms already exists, else false
 */
function _taxonomy_manager_voc_is_empty($vid) {
  $count = db_result(db_query_range("SELECT t.* FROM {term_data} t INNER JOIN {term_hierarchy} h ON t.tid = h.tid WHERE vid = %d AND h.parent = 0", $vid, 0, 1));
  if ($count == 0) {
    return true;
  }
  return false;
}

/**
 * deletes terms from the database
 * optional orphans (terms where parent get deleted) can be deleted as well
 * 
 * (difference to taxonomy_del_term: deletion of orphans optional)
 *
 * @param $tids array of term id to delete
 * @param $options associative array with options
 *   if $options['delete_orphans'] is true, orphans get deleted
 */
function taxonomy_manager_delete_terms($tids, $options = array()) {
  if (!is_array($tids)) {
    array(
      $tids,
    );
  }
  while (count($tids) > 0) {
    $orphans = array();
    foreach ($tids as $tid) {
      if ($children = taxonomy_get_children($tid)) {
        foreach ($children as $child) {
          $parents = taxonomy_get_parents($child->tid);
          if ($options['delete_orphans']) {
            if (count($parents) == 1) {
              $orphans[] = $child->tid;
            }
          }
          else {
            db_query("DELETE FROM {term_hierarchy} WHERE tid = %d AND parent = %d", $child->tid, $tid);
            if (count($parents) == 1) {
              if (!db_result(db_query("SELECT COUNT(*) FROM {term_hierarchy} WHERE tid = %d AND parent = 0", $child->tid))) {
                db_query("INSERT INTO {term_hierarchy} (parent, tid) VALUES(0, %d)", $child->tid);
              }
            }
          }
        }
      }
      db_query('DELETE FROM {term_data} WHERE tid = %d', $tid);
      db_query('DELETE FROM {term_hierarchy} WHERE tid = %d', $tid);
      db_query('DELETE FROM {term_relation} WHERE tid1 = %d OR tid2 = %d', $tid, $tid);
      db_query('DELETE FROM {term_synonym} WHERE tid = %d', $tid);
      db_query('DELETE FROM {term_node} WHERE tid = %d', $tid);
      $term = (array) taxonomy_get_term($tid);
      module_invoke_all('taxonomy', 'delete', 'term', $term);
      $tids = $orphans;
    }
  }
}

/**
 * moves terms in hierarchies to other parents
 *
 * @param $parents 
 *   array of parent term ids to where children can be moved
 *   array should only contain more parents if multi hiearchy enabled 
 *   if array contains 0, terms get placed to first (root) level
 * @param $children
 *   array of term ids to move
 * @param $options
 *   array of additional options for moving
 *   'keep_old_parents': if true, exisiting parents doesn't get deleted (only possible with multi hierarchies)
 */
function taxonomy_manager_move($parents, $children, $options = array()) {
  if (!is_array($parents)) {
    array(
      $parents,
    );
  }
  foreach ($children as $child) {
    if (!$options['keep_old_parents']) {
      db_query("DELETE FROM {term_hierarchy} WHERE tid = %d", $child);
    }
    foreach ($parents as $parent) {
      db_query("INSERT INTO {term_hierarchy} (parent, tid) VALUES (%d, %d)", $parent, $child);
    }
  }
}

/**
 * merges terms into another term (main term), all merged term get added
 * to the main term as synonyms. 
 * term_node relations are updated automatically (node with one of merging terms gets main term assigned)
 * after all opterions are done (adding of hierarchies, relations is optional) merging
 * terms get deleted
 *
 * @param $main_term
 *   id of term where other terms get merged into
 * @param $merging_terms
 *   array of term ids, which get merged into main term and afterwards deleted
 * @param $options
 *   array with additional options, possible values:
 *   'collect_parents': if true, all parents of merging terms get added to main term (only possible with multi hierarchies)
 *   'collect_children': if true, all children of merging terms get added to main term
 *   'collect_relations': if true, all relations of merging terms are transfered to main term
 */
function taxonomy_manager_merge($main_term, $merging_terms, $options = array(), $new_inserted = TRUE) {
  $vid = db_result(db_query("SELECT vid FROM {term_data} WHERE tid = %d", $main_term));
  $voc = taxonomy_get_vocabulary($vid);
  $merging_terms_parents = array();
  if ($voc->hierarchy == 2 && $new_inserted && $options['collect_parents']) {
    db_query("DELETE FROM {term_hierarchy} WHERE parent = 0 AND tid = %d", $main_term);
  }

  //TODO: add hook, so that other modules can consider changes
  foreach ($merging_terms as $merge_term) {
    if ($merge_term != $main_term) {

      //update node-relations
      $sql = db_query("SELECT nid FROM {term_node} WHERE tid = %d", $merge_term);
      while ($obj = db_fetch_object($sql)) {
        $nid = $obj->nid;
        db_query("DELETE FROM {term_node} WHERE tid = %d AND nid = %d", $merge_term, $nid);
        if (!db_result(db_query("SELECT COUNT(*) FROM {term_node} WHERE tid = %d AND nid = %d", $main_term, $nid))) {
          db_query("INSERT INTO {term_node} (tid, nid) VALUES (%d, %d)", $main_term, $nid);
        }
      }
      if ($voc->hierarchy == 1) {

        //sinlge hierarchy
        $parents = taxonomy_get_parents($merge_term);
        $parent = array_shift($parents);
        $merging_terms_parents[$parent->tid] = $parent->tid;
      }
      if ($options['collect_parents']) {
        $parents = taxonomy_get_parents($merge_term);
        foreach ($parents as $parent_tid => $parent_term) {
          if (!db_result(db_query("SELECT COUNT(*) FROM {term_hierarchy} WHERE tid = %d AND parent = %d", $main_term, $parent_tid))) {
            db_query("INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)", $main_term, $parent_tid);
          }
        }
      }
      if ($options['collect_children']) {
        $children = taxonomy_get_children($merge_term);
        foreach ($children as $child_tid => $child_term) {
          if (!db_result(db_query("SELECT COUNT(*) FROM {term_hierarchy} WHERE tid = %d AND parent = %d", $child_tid, $main_term))) {
            db_query("INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)", $child_tid, $main_term);
          }
        }
      }
      if ($options['collect_relations']) {
        $relations = taxonomy_get_related($merge_term);
        foreach ($relations as $related_tid => $relation) {
          if ($relation->tid1 == $merge_term) {
            if (!db_result(db_query("SELECT COUNT(*) FROM {term_relation} WHERE tid1 = %d AND tid2 = %d", $main_term, $related_tid))) {
              db_query("INSERT INTO {term_relation} (tid1, tid2) VALUES (%d, %d)", $main_term, $related_tid);
            }
          }
          else {
            if ($relation->tid2 == $merge_term) {
              if (!db_result(db_query("SELECT COUNT(*) FROM {term_relation} WHERE tid2 = %d AND tid1 = %d", $main_term, $related_tid))) {
                db_query("INSERT INTO {term_relation} (tid2, tid1) VALUES (%d, %d)", $main_term, $related_tid);
              }
            }
          }
        }
      }

      //save merged term (and synonomys of merged term) as synonym
      $term = taxonomy_get_term($merge_term);
      $merge_term_synonyms = taxonomy_get_synonyms($merge_term);
      $merge_term_synonyms[] = $term->name;
      foreach ($merge_term_synonyms as $syn) {
        if (!db_result(db_query("SELECT COUNT(*) FROM {term_synonym} WHERE tid = %d AND name = '%s'", $main_term, $syn))) {
          db_query("INSERT INTO {term_synonym} (tid, name) VALUES (%d, '%s')", $main_term, $syn);
        }
      }
      taxonomy_manager_delete_terms(array(
        $merge_term,
      ));
    }
  }
  if ($voc->hierarchy == 1 && count($merging_terms_parents) == 1 && $new_inserted) {
    db_query("UPDATE {term_hierarchy} SET parent = %d WHERE tid = %d", array_shift($merging_terms_parents), $main_term);
  }
  taxonomy_manager_merge_history_update($main_term, $merging_terms);
}

/**
 * inserts merging information (main_tid - merged_tid ) into taxonomy_manager_merge
 * and updates cache, which is used to reconstructs taxonomy/term pages
 *
 * @param $main_tid term if of main term
 * @param $merged_tids array of merged term ids
 */
function taxonomy_manager_merge_history_update($main_tid, $merged_tids) {
  if (!is_array($merged_tids)) {
    (array) $merged_tids;
  }
  foreach ($merged_tids as $merged_tid) {
    if ($merged_tid != $main_tid) {

      //check if merged term has been a main term once before
      $check_merged = db_result(db_query("SELECT COUNT(*) FROM {taxonomy_manager_merge} WHERE main_tid = %d", $merged_tid));
      if ($check_merged) {
        db_query("UPDATE {taxonomy_manager_merge} SET main_tid = %d WHERE main_tid = %d", $main_tid, $merged_tid);
      }

      //insert into merging history
      db_query("INSERT INTO {taxonomy_manager_merge} (main_tid, merged_tid) VALUES (%d, %d)", $main_tid, $merged_tid);
    }
  }
  taxonomy_manager_merge_history_update_cache();
}

/**
 * sets / updates cache for merging history
 */
function taxonomy_manager_merge_history_update_cache() {
  $merged_terms = array();
  $result = db_query("SELECT * FROM {taxonomy_manager_merge}");
  while ($data = db_fetch_object($result)) {
    $merged_terms[$data->merged_tid] = $data->main_tid;
  }
  cache_set('taxonomy_manager_merge', 'cache', serialize($merged_terms));
}

/**
 * helper function for getting out the main term of former merged term (which no 
 * long exists)
 *
 * @param $tid of which the main term has to be evaluated
 * @return term id of main term, if exists, else 0
 */
function taxonomy_manager_merge_get_main_term($tid) {
  $merged_terms = array();
  $cache = cache_get('taxonomy_manager_merge', 'cache');
  if (!$cache) {
    taxonomy_manager_merge_history_update_cache();
  }
  $merged_terms = unserialize($cache->data);
  return $merged_terms[$tid];
}

/**
 * menu callback 
 * 
 * replaces taxonomy_mangager_term_page, because we have to consider that the
 * url may contain former merged terms, which no longer exists
 * every given tid gets checked, if it has been merged. if yes, the tid gets replaced
 * with tid of main term and afterwards passed to default taxonomy_manager_term_page
 *
 * @param $str_tids
 * @param $depth
 * @param $op
 */
function taxonomy_manager_term_page($str_tids = '', $depth = 0, $op = 'page') {
  $tids = taxonomy_terms_parse_string($str_tids);
  if ($tids['operator'] == 'and' || $tids['operator'] == 'or') {
    $new_tids = array();
    foreach ($tids['tids'] as $tid) {

      //get cached main term, if not merged, returns 0
      $main_term = taxonomy_manager_merge_get_main_term($tid);
      $new_tids[] = $main_term ? $main_term : $tid;
    }
    if ($tids['operator'] == 'and') {
      $operator = ',';
    }
    else {
      if ($tids['operator'] == 'or') {
        $operator = '+';
      }
    }
    $new_tids_str = implode($operator, $new_tids);
    return taxonomy_term_page($new_tids_str, $depth, $op);
  }
  else {
    drupal_not_found();
  }
}

/**
 * helper function for getting out of term ids from autocomplete fields
 * non-exsiting terms get inserted autmatically
 * (part of taxonomy_node_save)
 *
 * @param $typed_input input string of form field
 * @param $vid vocabulary id
 * @return array of term ids
 */
function taxonomy_manager_autocomplete_tags_get_tids($typed_input, $vid, $insert_new = TRUE) {
  $tids = array();
  $regexp = '%(?:^|,\\ *)("(?>[^"]*)(?>""[^"]* )*"|(?: [^",]*))%x';
  preg_match_all($regexp, $typed_input, $matches);
  $typed_terms = array_unique($matches[1]);
  foreach ($typed_terms as $typed_term) {
    $typed_term = str_replace('""', '"', preg_replace('/^"(.*)"$/', '\\1', $typed_term));
    $typed_term = trim($typed_term);
    if ($typed_term == "") {
      continue;
    }
    $possibilities = taxonomy_get_term_by_name($typed_term);
    $typed_term_tid = NULL;

    // tid match if any.
    foreach ($possibilities as $possibility) {
      if ($possibility->vid == $vid) {
        $typed_term_tid = $possibility->tid;
        $tids[$typed_term_tid]['tid'] = $typed_term_tid;
      }
    }
    if (!$typed_term_tid && $insert_new) {
      $edit = array(
        'vid' => $vid,
        'name' => $typed_term,
      );
      $status = taxonomy_save_term($edit);
      $typed_term_tid = $edit['tid'];
      $tids[$typed_term_tid]['tid'] = $typed_term_tid;
      $tids[$typed_term_tid]['new'] = TRUE;
    }
  }
  return $tids;
}

/**
 * callback for updating weights
 * data send through AJAX, $_POST
 * $_POST[$tid] => $weight
 *
 */
function taxonomy_manager_update_weights($vid) {
  $weights = $_POST;
  if (is_array($weights)) {
    foreach ($weights as $tid => $weight) {
      if (is_numeric($tid) && is_numeric($weight)) {
        if (_taxonomy_manager_tree_term_valid($tid, $vid)) {
          db_query("UPDATE {term_data} SET weight = %d WHERE tid = %d", $weight, $tid);
        }
      }
    }
  }
  exit;
}

/** 
 * AJAX Callback that returns the CSV Output
 */
function taxonomy_manager_export() {
  $edit = $_POST;
  $output = taxonomy_manager_export_csv($edit['delimiter'], $edit['vid'], $edit['tid'], array(
    $edit['option'] => TRUE,
  ));
  print $output;
  exit;
}

/** 
 * Generates the CVS Ouput
 */
function taxonomy_manager_export_csv($delimiter = ";", $vid, $selected_tid = 0, $options = array()) {
  $tree = taxonomy_manager_export_get_tree($vid, $selected_tid, $options);
  foreach ($tree as $term) {
    $array = array();
    $array[] = '"' . $term->vid . '"';
    $array[] = '"' . $term->tid . '"';
    $array[] = '"' . $term->name . '"';
    $array[] = '"' . $term->description . '"';
    foreach ($term->parents as $parent) {
      $array[] = '"' . $parent . '"';
    }
    $output .= implode($delimiter, $array) . "\n";
  }
  return $output;
}

/**
 * Helper for cvs export to get taxonomy tree
 */
function taxonomy_manager_export_get_tree($vid, $selected_tid, $options) {
  $tree = array();
  if ($options['whole_voc']) {
    $tree = taxonomy_get_tree($vid);
  }
  else {
    if ($options['children'] && $selected_tid) {
      $tree = taxonomy_get_tree($vid, $selected_tid);
    }
    else {
      if ($options['root_terms']) {
        $tree = taxonomy_get_tree($vid, 0, -1, 1);
      }
    }
  }
  return $tree;
}

/**
 * theme function for taxonomy manager form
 */
function theme_taxonomy_manager_form($form) {
  $pager = theme('pager', NULL, variable_get('taxonomy_manager_pager_tree_page_size', 50), 0);
  $tree = drupal_render($form['taxonomy']);
  $term_data = drupal_render($form['term_data']);
  $top = drupal_render($form);
  $output = $top . $pager;
  $output .= '<div id="taxonomy-manager">';
  $output .= $tree;
  $output .= '<div id="taxonomy-term-data">';
  $output .= $term_data;
  $output .= '</div>';
  $output .= '<div class="clear" />';
  $output .= '</div>';
  return $output;
}

/**
 * themes a real button form type (no form submit)
 */
function theme_no_submit_button($element) {

  // Make sure not to overwrite classes.
  if (isset($element['#attributes']['class'])) {
    $element['#attributes']['class'] = 'form-' . $element['#button_type'] . ' ' . $element['#attributes']['class'];
  }
  else {
    $element['#attributes']['class'] = 'form-' . $element['#button_type'];
  }
  return '<input type="button" ' . (empty($element['#name']) ? '' : 'name="' . $element['#name'] . '" ') . 'id="' . $element['#id'] . '" value="' . check_plain($element['#value']) . '" ' . drupal_attributes($element['#attributes']) . " />\n";
}

/**
 * themes a image type button
 */
function theme_taxonomy_manager_image_button($element) {

  //Make sure not to overwrite classes
  if (isset($element['#attributes']['class'])) {
    $element['#attributes']['class'] = 'form-' . $element['#button_type'] . ' ' . $element['#attributes']['class'];
  }
  else {
    $element['#attributes']['class'] = 'form-' . $element['#button_type'];
  }

  // here the novelty begins: check if #button_type is normal submit button or image button
  $return_string = '<input ';
  if ($element['#button_type'] == 'image') {
    $return_string .= 'type="image" ';
  }
  else {
    $return_string .= 'type="submit" ';
  }
  $return_string .= empty($element['#id']) ? '' : 'id="' . $element['#id'] . '" ';
  $return_string .= empty($element['#name']) ? '' : 'name="' . $element['#name'] . '" ';
  $return_string .= 'value="' . check_plain($element['#value']) . '" ';
  $return_string .= drupal_attributes($element['#attributes']) . " />\n";
  return $return_string;
}

/******************************************
 * TAXONOMY TREE FORM ELEMENT DEFINITION
 * 
 * how to use:
 * $form['name'] = array( 
 *   '#type' => 'taxonomy_manager_tree', 
 *   '#vid' => $vid,
 * );
 * 
 * additional parameter:
 *   #pager: TRUE / FALSE, 
 *     whether to use pagers (drupal pager, load of nested children, load of siblings) 
 *     or to load the whole tree on page generation
 *   #parent: only children on this parent will be loaded
 *   #siblings_page: current page for loading pf next siblings, internal use
 * 
 * defining term operations:
 *   to add values (operations,..) to each term, add a function, which return a form array
 *   'tree_form_id'_operations
 * 
 * how to retrieve selected values:
 *   selected terms ids are available in validate / submit function in
 *   $form_values['name']['selected_terms'];
 * 
 ******************************************/

/**
 * Implementation of hook_elements
 */
function taxonomy_manager_elements() {
  $type['taxonomy_manager_tree'] = array(
    '#input' => TRUE,
    '#process' => array(
      'taxonomy_manager_tree_process_elements' => array(),
    ),
    '#tree' => TRUE,
  );
  return $type;
}

/**
 * Processes the tree form element
 * 
 * @param $element
 * @return the tree element
 */
function taxonomy_manager_tree_process_elements($element) {
  $module_path = drupal_get_path('module', 'taxonomy_manager') . '/';
  $id = form_clean_id(implode('-', $element['#parents']));
  $vid = $element['#vid'];
  if (!$element['#parent'] && !$element['#siblings_page']) {
    drupal_add_css($module_path . 'css/taxonomy_manager.css');
    drupal_add_js($module_path . 'js/tree.js');
    drupal_add_js($module_path . 'js/childForm.js');
    drupal_add_js($module_path . 'js/siblingsForm.js');
    drupal_add_js(array(
      'siblingsForm' => array(
        'url' => url('admin/content/taxonomy_manager/siblingsform'),
        'modulePath' => $module_path,
      ),
    ), 'setting');
    drupal_add_js(array(
      'childForm' => array(
        'url' => url('admin/content/taxonomy_manager/childform'),
        'modulePath' => $module_path,
      ),
    ), 'setting');
    drupal_add_js(array(
      'taxonomy_manager' => array(
        'modulePath' => url($module_path) == $module_path ? $module_path : base_path() . $module_path,
      ),
    ), 'setting');
    drupal_add_js(array(
      'taxonomytree' => array(
        'id' => $id,
        'vid' => $vid,
      ),
    ), 'setting');
  }
  if (!is_array($element['#operations'])) {
    $opertions_callback = implode('_', $element['#parents']) . '_operations';
    if (function_exists($opertions_callback)) {
      $element['#operations'] = $opertions_callback();
    }
  }
  if (!isset($element['#link'])) {
    $link_callback = implode('_', $element['#parents']) . '_link';
    if (function_exists($link_callback)) {
      $element['#link'] = $link_callback($vid);
    }
  }
  $tree = _taxonomy_manager_tree_get_item($element['#vid'], $element['#parent'], $element['#pager'], $element['#siblings_page'], $element['#search_string']);
  if ($element['#pager'] && !($element['#parent'] || $element['#siblings_page'])) {
    $element['pager'] = array(
      '#value' => theme('pager', NULL, variable_get('taxonomy_manager_pager_tree_page_size', 50)),
    );
  }
  $element['#tree'] = TRUE;
  $element['#id'] = $id;
  $element['#validate'] = array(
    'taxonomy_manager_tree_validate' => array(),
  );
  $element['selected_terms'] = array(
    '#type' => 'value',
    '#value' => array(),
  );
  taxonomy_manager_tree_build_form($index = 0, $tree, $element['#elements'], $element, $element['#parents'], !$element['#pager'], $element['#siblings_page']);
  return $element;
}

/**
 * loads tree with terms (depending on various settings)
 *
 * @param $vid
 * @param $parent
 * @param $pager
 * @param $siblings_page
 * @return array with term elements
 */
function _taxonomy_manager_tree_get_item($vid, $parent = 0, $pager = FALSE, $siblings_page = 0, $search_string = NULL) {
  $tree = array();
  if ($pager) {
    if ($parent || $siblings_page) {
      $start = ($siblings_page - 1) * variable_get('taxonomy_manager_pager_tree_page_size', 50);
      $result = db_query_range("SELECT t.* FROM {term_data} t INNER JOIN {term_hierarchy} h ON t.tid = h.tid WHERE vid = %d AND h.parent = %d ORDER BY weight, name", $vid, $parent, $start, variable_get('taxonomy_manager_pager_tree_page_size', 50));
    }
    else {
      if ($search_string) {
        $result = pager_query("SELECT t.* FROM {term_data} t INNER JOIN {term_hierarchy} h ON t.tid = h.tid WHERE vid = %d AND h.parent = 0 AND name LIKE ('%%%s%%') ORDER BY weight, name", variable_get('taxonomy_manager_pager_tree_page_size', 50), 0, NULL, array(
          $vid,
          $search_string,
        ));
      }
      else {
        $result = pager_query("SELECT t.* FROM {term_data} t INNER JOIN {term_hierarchy} h ON t.tid = h.tid WHERE vid = %d AND h.parent = 0 ORDER BY weight, name", variable_get('taxonomy_manager_pager_tree_page_size', 50), 0, NULL, array(
          $vid,
        ));
      }
    }
    while ($term = db_fetch_object($result)) {
      $tree[] = $term;
    }
  }
  else {
    $tree = taxonomy_get_tree($vid, $parent);
  }
  return $tree;
}

/**
 * recursive function for building nested form array 
 * with checkboxes and weight forms for each term
 * 
 * nested form array are allways appended to parent-form['children'] 
 *
 * @param $index current index in tree, start with 0
 * @param $tree of terms (generated by taxonomy_get_tree)
 * @return a form array 
 */
function taxonomy_manager_tree_build_form(&$index, $tree, &$form, $root_form, $parents = array(), $build_subtrees = TRUE, $page = 0) {
  $current_depth = $tree[$index]->depth;
  while ($index < count($tree) && $tree[$index]->depth >= $current_depth) {
    $term = $tree[$index];
    $attributes = array();
    $this_parents = $parents;
    $this_parents[] = $term->tid;
    $form[$term->tid]['checkbox'] = array(
      '#type' => 'checkbox',
      '#title' => $term->name,
      '#return_value' => 1,
      '#theme' => 'taxonomy_manager_tree_checkbox',
    );
    if ($root_form['#link']) {
      $form[$term->tid]['checkbox']['#link'] = $root_form['#link'] . '/' . $term->tid;
    }
    $form[$term->tid]['weight'] = array(
      '#type' => 'hidden',
      '#value' => $term->weight,
      '#attributes' => array(
        'class' => 'weight-form',
      ),
    );
    $form[$term->tid]['tid'] = array(
      '#type' => 'hidden',
      '#value' => $term->tid,
      '#attributes' => array(
        'class' => 'term-id',
      ),
    );
    if (is_array($root_form['#operations'])) {
      $form[$term->tid]['operations'] = $root_form['#operations'];
    }
    if ($page) {
      if ($index == variable_get('taxonomy_manager_pager_tree_page_size', 50) - 1) {
        $module_path = drupal_get_path('module', 'taxonomy_manager') . '/';
        $form[$term->tid]['has-more-siblings'] = array(
          '#type' => 'markup',
          '#value' => theme("image", $module_path . "images/2downarrow.png", "more", NULL, array(
            'class' => 'load-siblings',
          )),
        );
        $form[$term->tid]['page'] = array(
          '#type' => 'hidden',
          '#value' => $page,
          '#attributes' => array(
            'class' => 'page',
          ),
        );
        $next_count = _taxonomy_manager_tree_get_next_siblings_count($term->vid, $page, $root_form['#parent']);
        $form[$term->tid]['next_count'] = array(
          '#value' => $next_count,
        );
        $form[$term->tid]['#attributes']['class'] .= 'has-more-siblings ';
      }
    }
    _taxonomy_manager_tree_element_set_params($this_parents, $form[$term->tid]);
    $index++;
    if ($build_subtrees) {
      if ($tree[$index]->depth > $current_depth) {
        $form[$term->tid]['#attributes']['class'] .= _taxonomy_manager_tree_term_get_class($index - 1, $tree);
        taxonomy_manager_tree_build_form($index, $tree, $form[$term->tid]['children'], $root_form, array_merge($this_parents, array(
          'children',
        )));
      }
      else {
        if (count($tree) - 1 == $index - 1 || $tree[$index]->depth < $current_depth) {
          $form[$term->tid]['#attributes']['class'] .= 'last ';
        }
      }
    }
    else {
      if (_taxonomy_manager_tree_term_has_children($term->tid)) {
        $form[$term->tid]['#attributes']['class'] .= 'has-children ';
        if ($index - 1 == count($tree) - 1) {
          $form[$term->tid]['#attributes']['class'] .= 'lastExpandable ';
        }
        else {
          $form[$term->tid]['#attributes']['class'] .= 'expandable ';
        }
      }
      else {
        if ($index - 1 == count($tree) - 1) {
          $form[$term->tid]['#attributes']['class'] .= 'last ';
        }
      }
    }
  }
}

/**
 * adds #id and #name to all form elements
 *
 * @param $parents
 * @param $form
 */
function _taxonomy_manager_tree_element_set_params($parents, &$form) {
  foreach (element_children($form) as $field_name) {
    $field_parents = array_merge($parents, array(
      $field_name,
    ));
    $form[$field_name]['#tree'] = TRUE;
    $form[$field_name]['#post'] = array();
    $form[$field_name]['#parents'] = $field_parents;
    $form[$field_name]['#id'] = form_clean_id('edit-' . implode('-', $field_parents));
    $form[$field_name]['#name'] = array_shift($field_parents) . '[' . implode('][', $field_parents) . ']';
  }
}

/**
 * calculates class type (expandable, lastExpandable) for current element
 *
 * @param $current_index in tree array
 * @param $tree array with terms
 * @return expandable or lastExpandable
 */
function _taxonomy_manager_tree_term_get_class($current_index, $tree) {
  $class = '';
  $term = $tree[$current_index];
  $next = $tree[++$current_index];
  $children = false;
  while ($next->depth > $term->depth) {
    $children = true;
    $next = $tree[++$current_index];
  }
  if ($next->depth == $term->depth) {
    $class = 'expandable ';
  }
  else {
    $class = 'lastExpandable ';
  }
  return $class;
}

/**
 * checks if a term has children
 *
 * @param $tid
 * @return true, if term has children, else false
 */
function _taxonomy_manager_tree_term_has_children($tid) {
  $count = db_result(db_query("SELECT COUNT(tid) FROM {term_hierarchy} WHERE parent = %d", $tid));
  if ($count == 0) {
    return false;
  }
  return true;
}

/**
 * calculates number of next siblings if using paging
 *
 * @param $vid
 * @param $page
 * @param $parent
 * @return next page size
 */
function _taxonomy_manager_tree_get_next_siblings_count($vid, $page, $parent = 0) {
  $count = db_result(db_query("SELECT COUNT(t.tid) FROM {term_data} t INNER JOIN {term_hierarchy} h ON t.tid = h.tid WHERE vid = %d AND h.parent = %d", $vid, $parent));
  $current_count = variable_get('taxonomy_manager_pager_tree_page_size', 50) * $page;
  $diff = $count - $current_count;
  if ($diff > variable_get('taxonomy_manager_pager_tree_page_size', 50)) {
    $diff = variable_get('taxonomy_manager_pager_tree_page_size', 50);
  }
  return $diff;
}

/**
 * callback for generating and rendering nested child forms (AHAH)
 *
 * @param $tree_id 
 * @param $parent term id of parent, that is expanded and of which children have to be loaded
 */
function taxonomy_manager_tree_build_child_form($tree_id, $vid, $parent) {
  $GLOBALS['devel_shutdown'] = FALSE;

  //prevent devel queries footprint
  $child_form = array(
    '#type' => 'taxonomy_manager_tree',
    '#vid' => $vid,
    '#parent' => $parent,
    '#pager' => TRUE,
  );
  if (!$root_level) {
    $child_form['#siblings_page'] = 1;
  }
  $opertions_callback = str_replace('-', '_', $tree_id) . '_operations';
  if (function_exists($opertions_callback)) {
    $child_form['#operations'] = $opertions_callback();
  }
  $link_callback = str_replace('-', '_', $tree_id) . '_link';
  if (function_exists($link_callback)) {
    $child_form['#link'] = $link_callback($vid);
  }
  _taxonomy_manager_tree_sub_forms_set_parents($tree_id, $parent, $child_form);
  $child_form = form_builder('taxonomy_manager_form', $child_form);
  print drupal_render($child_form);
  exit;
}

/**
 * callback for generating and rendering next siblings terms form (AHAH)
 *
 * @param $tree_id
 * @param $page current page
 * @param $prev_tid last sibling, that appears
 * @param $parent if in hierarchies, parent id
 */
function taxonomy_manager_tree_build_siblings_form($tree_id, $page, $prev_tid, $parent = 0) {
  $GLOBALS['devel_shutdown'] = FALSE;

  //prevent devel queries footprint
  $vid = db_result(db_query("SELECT vid FROM {term_data} WHERE tid = %d", $prev_tid));
  $siblings_form = array(
    '#type' => 'taxonomy_manager_tree',
    '#vid' => $vid,
    '#parent' => $parent,
    '#pager' => TRUE,
    '#siblings_page' => $page + 1,
  );
  $opertions_callback = str_replace('-', '_', $tree_id) . '_operations';
  if (function_exists($opertions_callback)) {
    $siblings_form['#operations'] = $opertions_callback();
  }
  $link_callback = str_replace('-', '_', $tree_id) . '_link';
  if (function_exists($link_callback)) {
    $siblings_form['#link'] = $link_callback($vid);
  }
  _taxonomy_manager_tree_sub_forms_set_parents($tree_id, $parent, $siblings_form);
  $siblings_form = form_builder('taxonomy_manager_form', $siblings_form);
  $output = drupal_render($siblings_form);

  //cutting of <ul> and ending </ul> ... can this be done cleaner?
  $output = drupal_substr($output, 4, -5);
  print $output;
  exit;
}

/**
 * sets parents depending on form_id and hierarchical parents
 *
 * @param $tree_id
 * @param $parent term id
 * @param $form
 */
function _taxonomy_manager_tree_sub_forms_set_parents($tree_id, $parent, &$form) {
  $tree_ids = explode('-', $tree_id);
  foreach ($tree_ids as $key => $id) {
    $form['#parents'][] = $id;
  }
  if ($parent) {
    $all_parents = taxonomy_get_parents_all($parent);
    for ($i = count($all_parents) - 1; $i >= 0; $i--) {
      $form['#parents'][] = $all_parents[$i]->tid;
      $form['#parents'][] = 'children';
    }
  }
}

/**
 * validates submitted form values
 * checks if selected terms really belong to initial voc, if not --> form_set_error
 * 
 * if all is valid, selected values get added to 'selected_terms' for easy use in submit
 *
 * @param $form
 */
function taxonomy_manager_tree_validate($form) {
  $selected = array();
  $selected = _taxonomy_manager_tree_get_selected_terms($form['#value']);
  $vid = $form['#vid'];
  foreach ($selected as $tid) {
    if (!_taxonomy_manager_tree_term_valid($tid, $vid)) {
      form_set_error('', t('An illegal choice has been detected. Please contact the site administrator.'));
    }
  }
  form_set_value($form['selected_terms'], $selected);
}

/**
 * checks if term id belongs to vocabulary
 *
 * @param $tid term id
 * @param $vid voc id
 * @return true, if term belongs to voc, else false
 */
function _taxonomy_manager_tree_term_valid($tid, $vid) {
  $term = taxonomy_get_term($tid);
  if ($term->vid != $vid) {
    return false;
  }
  return true;
}

/**
 * returns term ids of selected checkboxes
 * 
 * goes through nested form array recursivly
 * 
 * @param $form_values
 * @return an array with ids of selected terms
 */
function _taxonomy_manager_tree_get_selected_terms($form_values) {
  $tids = array();
  if (is_array($form_values)) {
    foreach ($form_values as $tid => $form_value) {
      if ($form_value['checkbox']) {
        $tids[$tid] = $tid;
      }
      if (is_array($form_value['children'])) {
        $tids += _taxonomy_manager_tree_get_selected_terms($form_value['children']);
      }
    }
  }
  return $tids;
}

/**
 * theme function for root element
 *
 * @param $element
 * @return html output
 */
function theme_taxonomy_manager_tree(&$element) {
  $tree = theme('taxonomy_manager_tree_elements', $element['#elements']);
  if (!$element['#parent'] && !$element['#siblings_page']) {
    $output = '<div id="' . $element['#id'] . '">';
    $output .= $tree;
    $output .= '</div>';
    return theme('form_element', $element, $output);
  }
  return $tree;
}

/**
 * recursive theme function for term elements
 *
 * @param $element
 * @return html lists
 */
function theme_taxonomy_manager_tree_elements($element) {
  $output .= "<ul>";
  if (is_array($element)) {
    foreach (element_children($element) as $tid) {
      if (is_numeric($tid)) {
        $output .= '<li' . drupal_attributes($element[$tid]['#attributes']) . '>';
        $output .= '<div class="term-line">';
        $output .= '<div class="term-item">';
        $output .= drupal_render($element[$tid]['checkbox']);
        $output .= '</div>';
        $output .= '<div class="term-operations">';
        $output .= drupal_render($element[$tid]['operations']);
        $output .= '</div>';
        $output .= drupal_render($element[$tid]['weight']);
        $output .= drupal_render($element[$tid]['tid']);
        if (is_array($element[$tid]['has-more-siblings'])) {
          $output .= '<div class="term-has-more-siblings">';
          $output .= '<div class="term-next-count">next ' . drupal_render($element[$tid]['next_count']) . '</div>';
          $output .= '<div class="term-downarrow-img">';
          $output .= drupal_render($element[$tid]['has-more-siblings']);
          $output .= drupal_render($element[$tid]['page']);
          $output .= '</div><div class="clear"></div></div>';
        }
        $output .= '<div class="clear"> </div></div>';
        if (is_array($element[$tid]['children'])) {
          $output .= theme('taxonomy_manager_tree_elements', $element[$tid]['children']);
        }
        if (strstr($element[$tid]['#attributes']['class'], 'has-children')) {
          $output .= "<ul><li></li></ul>";
        }
        $output .= '</li>';
      }
    }
  }
  $output .= "</ul>";
  return $output;
}

/**
 * themes a checkbox, where a label can optional contain a link
 */
function theme_taxonomy_manager_tree_checkbox($element) {
  _form_set_class($element, array(
    'form-checkbox',
  ));
  $checkbox = '<input ';
  $checkbox .= 'type="checkbox" ';
  $checkbox .= 'name="' . $element['#name'] . '" ';
  $checkbox .= 'id="' . $element['#id'] . '" ';
  $checkbox .= 'value="' . $element['#return_value'] . '" ';
  $checkbox .= $element['#value'] ? ' checked="checked" ' : ' ';
  $checkbox .= drupal_attributes($element['#attributes']) . ' />';
  $title = $element['#title'];
  if ($element['#link']) {
    $title = l($title, $element['#link'], array(
      "class" => "term-data-link",
    ));
  }
  else {
    $title = check_plain($title);
  }
  if (!is_null($title)) {
    $checkbox = '<label class="option">' . $checkbox . ' ' . $title . '</label>';
  }
  unset($element['#title']);
  return theme('form_element', $element, $checkbox);
}

Functions

Namesort descending Description
taxonomy_manager_add_form form for adding terms
taxonomy_manager_autocomplete_tags_get_tids helper function for getting out of term ids from autocomplete fields non-exsiting terms get inserted autmatically (part of taxonomy_node_save)
taxonomy_manager_confirm_delete confirmation form for deleting selected terms
taxonomy_manager_delete_terms deletes terms from the database optional orphans (terms where parent get deleted) can be deleted as well
taxonomy_manager_elements Implementation of hook_elements
taxonomy_manager_export AJAX Callback that returns the CSV Output
taxonomy_manager_export_csv Generates the CVS Ouput
taxonomy_manager_export_form form for exporting terms
taxonomy_manager_export_get_tree Helper for cvs export to get taxonomy tree
taxonomy_manager_form defines forms for taxonomy manager interface
taxonomy_manager_form_submit submits the taxonomy manager form
taxonomy_manager_form_term_data term data editing form
taxonomy_manager_form_validate validates the form
taxonomy_manager_help Implementation of hook_help().
taxonomy_manager_menu Implementation of hook_menu
taxonomy_manager_merge merges terms into another term (main term), all merged term get added to the main term as synonyms. term_node relations are updated automatically (node with one of merging terms gets main term assigned) after all opterions are done (adding of…
taxonomy_manager_merge_form form for merging terms
taxonomy_manager_merge_get_main_term helper function for getting out the main term of former merged term (which no long exists)
taxonomy_manager_merge_history_update inserts merging information (main_tid - merged_tid ) into taxonomy_manager_merge and updates cache, which is used to reconstructs taxonomy/term pages
taxonomy_manager_merge_history_update_cache sets / updates cache for merging history
taxonomy_manager_move moves terms in hierarchies to other parents
taxonomy_manager_move_form form for moving terms in hierarchies
taxonomy_manager_settings Defines a settings form.
taxonomy_manager_terms_confirm_delete Additional confirmation form for deletion
taxonomy_manager_terms_confirm_delete_submit Submit handler for deletion confirmation form
taxonomy_manager_term_data_edit callback handler for updating term data
taxonomy_manager_term_page menu callback
taxonomy_manager_tree_build_child_form callback for generating and rendering nested child forms (AHAH)
taxonomy_manager_tree_build_form recursive function for building nested form array with checkboxes and weight forms for each term
taxonomy_manager_tree_build_siblings_form callback for generating and rendering next siblings terms form (AHAH)
taxonomy_manager_tree_link function gets called by taxonomy_manager_tree form type (form_id +_link) and returns an link, where to go, when a term gets clicked
taxonomy_manager_tree_operations function gets called by the taxonomy_manager_tree form type (form_id +_operations) return an form array with values to show next to every term value
taxonomy_manager_tree_process_elements Processes the tree form element
taxonomy_manager_tree_validate validates submitted form values checks if selected terms really belong to initial voc, if not --> form_set_error
taxonomy_manager_update_term_data_form menu callback for displaying term data form
taxonomy_manager_update_weights callback for updating weights data send through AJAX, $_POST $_POST[$tid] => $weight
taxonomy_manager_voc returns either form for deletion confirm or the taxonomy manager form
taxonomy_manager_voc_list list of vocabularies, which link to Taxonomy Manager interface
theme_no_submit_button themes a real button form type (no form submit)
theme_taxonomy_manager_form theme function for taxonomy manager form
theme_taxonomy_manager_image_button themes a image type button
theme_taxonomy_manager_tree theme function for root element
theme_taxonomy_manager_tree_checkbox themes a checkbox, where a label can optional contain a link
theme_taxonomy_manager_tree_elements recursive theme function for term elements
_taxonomy_manager_form_term_data_lists helper function for generating tables with values and delete op and field for adding
_taxonomy_manager_tree_element_set_params adds #id and #name to all form elements
_taxonomy_manager_tree_get_item loads tree with terms (depending on various settings)
_taxonomy_manager_tree_get_next_siblings_count calculates number of next siblings if using paging
_taxonomy_manager_tree_get_selected_terms returns term ids of selected checkboxes
_taxonomy_manager_tree_sub_forms_set_parents sets parents depending on form_id and hierarchical parents
_taxonomy_manager_tree_term_get_class calculates class type (expandable, lastExpandable) for current element
_taxonomy_manager_tree_term_has_children checks if a term has children
_taxonomy_manager_tree_term_valid checks if term id belongs to vocabulary
_taxonomy_manager_voc_is_empty checks if voc has terms