\n");
}
if (!count($selected)) {
return array('info' => array('#value' => t('No terms selected.') .' '. 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 .= '
';
$output .= $tree;
$output .= '
';
$output .= $term_data;
$output .= '
';
$output .= '';
$output .= '
';
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 '\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 = '\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
and ending
... 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 = '
';
$output .= $tree;
$output .= '
';
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 .= "
";
if (is_array($element)) {
foreach (element_children($element) as $tid) {
if (is_numeric($tid)) {
$output .= '