? LICENSE.txt ? hide_show_root_level.patch ? per-vocabulary_directory.patch ? refactored.patch Index: directory.css =================================================================== RCS file: /cvs/drupal/contributions/modules/directory/directory.css,v retrieving revision 1.4.2.3 diff -u -F^f -r1.4.2.3 directory.css --- directory.css 8 Jun 2007 12:00:41 -0000 1.4.2.3 +++ directory.css 21 Jul 2007 14:44:39 -0000 @@ -1,40 +1,26 @@ .directory-home-vocabulary { } .directory-child-vocabulary { } -.directory-resources { } .directory-sub-categories { } .directory-category { } -.directory-toolbar { } -.directory-filter-wrapper { } - -/* "View all" text and link div */ -div.directory-all-resources { margin-left: 2em; } -div.directory-all-resources span.directory-term-name { font-style:italic; } -div.directory-all-resources span.directory-limit { font-style: italic; } -div.directory-all-resources a { font-weight:bold; } .directory-help, .directory-term-help { border: solid 1px #eee; padding: 1em; } -.directory-no-resources-available { font-weight: bold; color:red; padding: 1em;} /* control appearance of taxonomy terms in top-level views */ span.directory-category-haschildren { font-weight:bold; } /* has 1 or more child nodes */ span.directory-category-nochildren { } /* has no child nodes */ span.directory-nodecount { font-style:italic; font-size: .9em; color: #555; } /* what to do with (nnn) span after term? */ -table.directory-resources ul li { display: block; list-style:none; } -table.directory-resources { width: 98%; } -table.directory-resources { margin-top: 1em; margin-bottom: .25em; } -table.directory-resources tr td { width: 50%; } /* make columns evenly spaced */ - /* Controls the javascript collapsible vocabs on the main page */ div.directory-home-vocabulary-collapsible { margin-top: 1em; } -div.directory-home-vocabulary-collapsible h3{ +div.directory-home-vocabulary-collapsible h3 { display: inline; } -.directory-home-toggle-link { +.directory-home-toggle-link, +.directory-category-toggle-link { text-decoration: underline; color: blue; padding-left: 3em; @@ -46,3 +32,28 @@ color: red; } +div.directory-return-from-vocabulary-page { + margin: .5em; + font-size: .95em; + font-style: italic; +} + +div#directory-content-type-filters { + margin-top: 2em; + margin-bottom: 2em; + padding: 1em; + border: 1px dotted; +} + +div#directory-content-type-filters h4 { + clear: both; +} + +a.directory-content-type-filter-link { + margin: 1em; +} + +p.directory-filtered-by-content-type { + margin-top: 0.5em; + margin-bottom: 0; +} Index: directory.js =================================================================== RCS file: /cvs/drupal/contributions/modules/directory/Attic/directory.js,v retrieving revision 1.1.2.1 diff -u -F^f -r1.1.2.1 directory.js --- directory.js 8 Jun 2007 12:00:41 -0000 1.1.2.1 +++ directory.js 21 Jul 2007 14:44:39 -0000 @@ -3,7 +3,11 @@ $("div.directory-home-vocabulary-collapsed/div.item-list/ul").hide(); $("div.directory-home-vocabulary-collapsible//h3").after('' + toggleT + ''); $(".directory-home-toggle-link").click(function(){ - $(this).next("ul").toggle(); + $(this).next("ul").slideToggle("fast"); + }); + $("div.hierarchical-vocabulary/div/ul/li/div/ul").parent().before('' + toggleT + ''); + $(".directory-category-toggle-link").click(function(){ + $(this).next("div ul").slideToggle("fast"); }); }); } Index: directory.module =================================================================== RCS file: /cvs/drupal/contributions/modules/directory/directory.module,v retrieving revision 1.11.2.29 diff -u -F^f -r1.11.2.29 directory.module --- directory.module 16 Jul 2007 08:54:49 -0000 1.11.2.29 +++ directory.module 21 Jul 2007 14:44:39 -0000 @@ -1,19 +1,5 @@ */ -/* Original Frontier implementation by John VanDyk */ -/* Current maintainer Michael Curry, Exodus Development, Inc. http://exodusdev.com exodusdev@gmail.com */ - -// Examples: -// http://amadorable.com/directory -// http://www.ent.iastate.edu/list/ - -define('DIRECTORY_MODULE_VERSION', '$Id: directory.module,v 1.11.2.29 2007/07/16 08:54:49 augustin Exp $'); - - -/******************************************************************** - * Drupal Hooks :: General Overview - ********************************************************************/ /** * Implementation of hook_menu(). @@ -21,47 +7,51 @@ function directory_menu($may_cache) { $items = array(); - if (!$may_cache) { - drupal_add_css(drupal_get_path('module', 'directory') .'/directory.css'); - } - if ($may_cache) { $items[] = array( - 'path' => 'directory', - 'title' => t('directory'), - 'callback' => 'directory_page', - 'access' => user_access('access content') - ); - $items[] = array( - 'path' => 'directory/term', - 'title' => t('Advanced directory search'), - 'callback' => 'directory_term_page', - 'access' => user_access('access content'), - 'type' => MENU_CALLBACK - ); - $items[] = array( - 'path' => 'directory/random', - 'title' => t('Random directory link'), - 'callback' => 'directory_random', + 'path' => 'directory/random', + 'title' => t('Random directory link'), + 'callback' => 'directory_random_page', 'access' => user_access('access content'), - 'type' => MENU_CALLBACK + 'type' => MENU_CALLBACK, ); $items[] = array( 'path' => 'admin/settings/directory', - 'title' => t('Directory Settings'), + 'title' => t('Directory settings'), 'description' => t('Set which node types and which vocabularies to include, the depth to display on the directory page, etc.'), 'callback' => 'drupal_get_form', - 'callback arguments' => array('directory_admin_settings'), + 'callback arguments' => array('directory_admin_settings_form'), 'access' => user_access('administer site configuration'), - 'type' => MENU_NORMAL_ITEM + 'type' => MENU_NORMAL_ITEM, + ); + $items[] = array( + 'path' => 'directory', + 'title' => t('Directory'), + 'callback' => 'directory_page', + 'access' => user_access('access content'), + ); + $items[] = array( + 'path' => 'directory/term', + 'title' => t('Directory for term'), + 'callback' => 'directory_term_page', + 'access' => user_access('access content'), + 'type' => MENU_CALLBACK, ); + } + else { + drupal_add_css(drupal_get_path('module', 'directory') .'/directory.css'); + + // These menu items must all be created, because we are offering them as + // suggested menu items. This must in the !$maycache section, to make sure + // users can see new menu items or pages due to new vocabularies. (Their + // caches would not be updated automatically.) $vocabularies = taxonomy_get_vocabularies(); - foreach ($vocabularies AS $vid => $vocabulary) { + foreach ($vocabularies as $vid => $vocabulary) { $items[] = array( 'path' => 'directory/vocabulary/'. $vid, 'title' => t('Directory for !vocabulary-name', array('!vocabulary-name' => $vocabulary->name)), 'callback' => 'directory_vocabulary_page', - 'callback arguments' => $vid, + 'callback arguments' => array($vid), 'access' => user_access('access content'), 'type' => MENU_SUGGESTED_ITEM, ); @@ -71,16 +61,7 @@ function directory_menu($may_cache) { return $items; } -/******************************************************************** - * Drupal Hooks :: Core Hooks - ********************************************************************/ - -/** - * Implementation of hook_settings(). - */ -function directory_admin_settings() { - $output = ''; - +function directory_admin_settings_form() { if (function_exists('taxonomy_help')) { $vocs[0] = '<'. t('none') .'>'; foreach (taxonomy_get_vocabularies() as $vid => $voc) { @@ -89,25 +70,10 @@ function directory_admin_settings() { } $nodetypes = array(); - foreach (node_get_types() AS $type) { + foreach (node_get_types() as $type) { $nodetypes[$type->type] = $type->name; } - $form['module_banner'] = array( - '#type' => 'markup', - '#value' => '
Module development sponsored by - ', - ); - - $form['module_id'] = array( - '#type' => 'markup', - '#value' => DIRECTORY_MODULE_VERSION .'
', - ); - $form['directory_no_nodes'] = array( '#type' => 'checkboxes', '#title' => t('Exclude these node types from directory pages'), @@ -140,10 +106,10 @@ function directory_admin_settings() { $form['directory_show_child_counts'] = array( '#type' => 'checkbox', - '#title'=>t('Show count of nodes in categories'), + '#title'=> t('Show count of nodes in categories'), '#default_value' => variable_get('directory_show_child_counts', TRUE), '#description' => t('Append a count of items contained in each term, if the count is greater than zero.'), - '#required'=>FALSE, + '#required'=> FALSE, ); $form['directory_hide_empty_terms'] = array( @@ -151,151 +117,269 @@ function directory_admin_settings() { '#title'=>t('Hide terms with no content'), '#default_value' => variable_get('directory_hide_empty_terms', FALSE), '#description' => t('If checked, hide taxonomy terms having no node content.'), - '#required'=>FALSE, + '#required'=> FALSE, ); - + $form['directory_help'] = array( '#type' => 'textarea', '#title' => t('Help text for the Directory home'), '#default_value' => variable_get('directory_help', ''), '#cols' => 70, '#rows' => 5, - '#description' => t('This text will be displayed at the top of the main directory page. It is useful for helping or instructing your users.'), + '#description' => t('This text will be displayed at the top of the main directory page. It is useful for helping or instructing your users.'), ); $form['directory_term_help'] = array( '#type' => 'textarea', - '#title' => t('Help text for each Directory term page'), + '#title' => t('Help text for each directory term page'), '#default_value' => variable_get('directory_term_help', ''), '#cols' => 70, '#rows' => 5, - '#description' => t('This text will be displayed at the top of each directory term page. It is useful for helping or instructing your users.'), + '#description' => t('This text will be displayed at the top of each directory term page. It is useful for helping or instructing your users.'), ); return system_settings_form($form); } -/******************************************************************** - * Module Specific :: Public Functions - ********************************************************************/ +function directory_random_page() { + $nid = db_result(db_query('SELECT n.nid FROM {node} n WHERE n.status = 1 ORDER BY RAND() LIMIT 1')); + drupal_goto("node/$nid"); +} -/** - * This is the Controller for directory viewing. - */ -function directory_page($tid = null, $filter = null, $fid = null) { +function directory_page($content_type = NULL) { $output = ''; - if ($tid > 0) { //Display a category view - if ($help = variable_get('directory_term_help', '')) { - $output = '
'. $help .'
'; - } - directory_set_breadcrumb($tid, 'Home'); - $content .= theme('directory_resource', $tid, $filter, $fid); // can return NULL if nothing available - if (!$content) { - $output .= t('

There are no items in this category. Please choose another.

'); - } else { - $output .= $content; - } - } - elseif (preg_match('/^[a-zA-z]$/', $tid) || $tid == 'alpha' || $tid == '0-9') { - directory_set_breadcrumb($tid, 'Home'); - $output .= theme('directory_resource',$tid, $filter, $fid); - } - elseif (!empty($tid)) { - drupal_goto('directory'); + + if ($help = variable_get('directory_help', '')) { + $output = '
'. $help .'
'; } - else { //Display the root - if ($help = variable_get('directory_help', '')) { - $output = '
'. $help .'
'; - } - $allowed_vids = variable_get('directory_vocabularies_root', array()); - foreach (taxonomy_get_vocabularies() as $v) { - if (in_array($v->vid, $allowed_vids)) { - $output .= theme('directory_home_vocabulary', $v->vid); - } + + $allowed_vids = variable_get('directory_vocabularies_root', array()); + foreach (taxonomy_get_vocabularies() as $vocabulary) { + if (in_array($vocabulary->vid, $allowed_vids)) { + $tree = _directory_get_tree(taxonomy_get_children(0, $vocabulary->vid), $content_type); + $output .= theme('directory_vocabulary', $vocabulary, $tree, FALSE, TRUE, $content_type); } } + $output .= theme('directory_content_type_filters', $content_type); return $output; } -/** - * The controller for drilling into directories using multiple taxonomy term conditions. - * - * This functions the same as taxonomy_term_page, creating URLs like - * directory/term/5,2,48 - */ - -function directory_term_page($str_tids = '', $depth = 0, $op = 'page') { - +function directory_vocabulary_page($vid = NULL, $content_type = NULL) { $output = ''; - if (preg_match('/^([0-9]+[+ ])+[0-9]+$/', $str_tids)) { - $operator = 'or'; - // The '+' character in a query string may be parsed as ' '. - $tids = preg_split('/[+ ]/', $str_tids); - } - else if (preg_match('/^([0-9]+,)*[0-9]+$/', $str_tids)) { - $operator = 'and'; - $tids = explode(',', $str_tids); + + // If invalid vocabulary id, redirect to "directory". + $vocabulary = taxonomy_get_vocabulary($vid); + if (!$vocabulary) { + drupal_goto('directory'); } else { - return drupal_not_found(); + drupal_set_title(t("Directory for @vocabulary", array('@vocabulary' => $vocabulary->name))); + $tree = _directory_get_tree(taxonomy_get_children(0, $vid), $content_type); + + $output .= theme('directory_vocabulary', $vocabulary, $tree, FALSE, FALSE, $content_type); + $output .= theme('directory_content_type_filters', $content_type); + $output .= '
'. l(t('Return to directory'), 'directory') .'
'; } + return $output; +} - $tid_limit = 10; - $num_tids = count($tids); - if ($num_tids > $tid_limit) { - drupal_set_message(t('Please only chose up to %tid_limit categories. Your other category selections have been discarded.', array('%tid_limit' => $tid_limit))); - $tids = array_slice($tids, 0, $tid_limit); +/** + * Almost exact copy of taxonomy_term_page. Differences are: removed unused + * function parameters, added the $content_type parameter, used other nodes + * renderer (directory_render_nodes()), which removes the nodes that are not + * of the desired content type, modified breadcrumbs. + */ +function directory_term_page($str_tids = '', $content_type = NULL) { + $output = ''; + + $terms = taxonomy_terms_parse_string($str_tids); + if ($terms['operator'] != 'and' && $terms['operator'] != 'or') { + drupal_not_found(); } - // Build title: - if ($tids) { - $result = db_query('SELECT name FROM {term_data} WHERE tid IN (%s)', implode(',', $tids)); + if ($terms['tids']) { + $result = db_query(db_rewrite_sql('SELECT t.tid, t.name FROM {term_data} t WHERE t.tid IN (%s)', 't', 'tid'), implode(',', $terms['tids'])); + $tids = array(); // we rebuild the $tids-array so it only contains terms the user has access to. $names = array(); while ($term = db_fetch_object($result)) { + $tids[] = $term->tid; $names[] = $term->name; } - $title = implode(" $operator ", $names); - drupal_set_title($title); - } - switch ($op) { - case 'page': + if ($names) { + $title = check_plain(implode(', ', $names)); + drupal_set_title($title); + // Build breadcrumb based on first hierarchy of first term: $current->tid = $tids[0]; - $breadcrumbs = array(array('path' => $_GET['q'])); + $breadcrumbs = array(array('path' => $_GET['q'], 'title' => $names[0])); while ($parents = taxonomy_get_parents($current->tid)) { $current = array_shift($parents); - $breadcrumbs[] = array('path' => 'directory/'. $current->tid, 'title' => $current->name); + $breadcrumbs[] = array('path' => 'directory/term/'. $current->tid, 'title' => $current->name); } - $breadcrumbs = array_reverse($breadcrumbs); - menu_set_location($breadcrumbs); - $limit = 200; - $result = directory_select_nodes($tids, $operator, $depth, $limit); - $num_results = directory_select_count_nodes($tids, $operator, $depth, $limit); + // Now add the vocabulary name to the breadcrumbs. + $vocabulary = taxonomy_get_vocabulary($current->vid); + $breadcrumbs[] = array('path' => 'directory/vocabulary/'. $vocabulary->vid, 'title' => $vocabulary->name); + + // And finally, add "Directory" to the breadcrumbs. + $breadcrumbs[] = array('path' => 'directory', 'title' => t('Directory')); - if ($num_results == 0) { - drupal_set_message(t('No items match your criteria.')); - } - elseif (is_numeric($limit) && $num_results > $limit) { - drupal_set_message(t('Many results were found so you may want to refine your criteria. Showing the first %limit of %num_results resources.', array('%limit' => $limit, '%num_results' => $num_results))); - } + menu_set_location(array_reverse($breadcrumbs)); - $output = '

'. $title .'

'; - $output .= ''; + $result = _directory_select_nodes($tids, $terms['operator'], 25, $content_type); + + $output .= theme('directory_filtered_by_content_type', $content_type); + $output .= theme('directory_term', $result); + $output .= theme('directory_content_type_filters', $content_type); + $output .= '
'. l(t('Return to directory'), 'directory') .'
'; return $output; + } + } +} + +/** + * Helper function to build a vocabulary tree, that will contain meta + * information that will be used at the theme level. + * + * @param $terms + * The terms (the term objects) that will be at the root level of the tree + * that will be generated. + * @param $content_type + * Only the nodes of this content type should be counted. + * @return + * The generated tree with meta information. + */ +function _directory_get_tree($terms, $content_type = NULL) { + $show_counts = variable_get('directory_show_child_counts', TRUE); + $hide_empty = variable_get('directory_hide_empty_terms', FALSE); + + // Build a list of categories (taxonomy terms) and child counts. + foreach ($terms as $term) { + $tid = $term->tid; - default: - drupal_not_found(); + // Store the node count. + $tree[$tid]['nodecount'] = array('count_own' => 0, 'count_children' => 0); + if ($show_counts || $hide_empty) { + $tree[$tid]['nodecount'] = _directory_term_count_nodes($term->tid, $content_type); + } + + // Store the entire term, this is necessary for theming. + $tree[$tid]['term'] = $term; + // If desired, exclude empty items. + if ((!$hide_empty) || ($tree[$tid]['nodecount']['count_own'] || $tree[$tid]['nodecount']['count_children'])) { + $children = taxonomy_get_children($term->tid); + if (is_array($children)) { + $tree[$tid]['children'] = _directory_get_tree($children, $content_type); + } + } } + + // Tree format: + // $tree[$tid]['nodecount'] the node count information + // $tree[$tid]['term'] the original term object + // $tree[$tid]['children'] the tree below the current term + return $tree; +} + +/** + * This is a replacement function for taxonomy_term_count_nodes. + * See: http://drupal.org/node/144969 (drupal issue) + * and: http://drupal.org/node/145023 (directory issue). + * + * Count the number of published nodes classified by a term. + * + * @param $tid + * The term's ID + * @param $type + * The $node->type. If given, taxonomy_term_count_nodes only counts nodes of + * $type that are classified with the term $tid. + * @param $save_to_db + * This function is recursive, and we don't need to save the result in the DB at each iteration. + * $save_to_db is set to FALSE at each nested call, so that the actual saving to DB can happen only + * when the function exits the last time. + * + * @return $array + * where: + * $array['count_own'] being the number of nodes within the term proper. + * $array['count_children'] being the number of nodes in children terms, not counting those which are already counted in the parent term. + * $array['own_nodes'] array of nid's within this $tid. + * $array['children_nodes'] array of all the descendent nid's from children terms, not including those already set as one's own. + * + * Results are statically cached. + * Also, in order to improve performance accross requests, we cache the serialized array on database, in {cache_page} (this table is flushed each time a node or a taxonomy item is added/updated/deleted). + */ +function _directory_term_count_nodes($tid, $type = 0, $save_to_db = TRUE) { + static $count = array(); + $modified = FALSE; // We keep track of modification of $count, to check whether we need to save it to DB. + + if (empty($count)) { + $count = cache_get('taxonomy_term_count_nodes', 'cache_page'); + $count = unserialize($count->data); + } + + if (!isset($count[$type])) { + $modified = TRUE; + $count[$type] = array(); + // In the queries below, we cannot use 'SELECT t.tid, COUNT(n.nid) AS c FROM ...' + // because a node may be assigned more than one term and be counted more than once. + // We therefore take note of the nid's and count the number of items in the $count array, + // making sure there is no duplicate. + + // $type == 0 always evaluates TRUE if $type is a string + if (empty($type) || !is_string($type)) { + $result = db_query(db_rewrite_sql('SELECT t.tid, n.nid FROM {term_node} t JOIN {node} n ON t.nid = n.nid WHERE n.status = 1', 't', 'tid')); + } + else { + $result = db_query(db_rewrite_sql("SELECT t.tid, n.nid FROM {term_node} t JOIN {node} n ON t.nid = n.nid WHERE n.status = 1 AND n.type = '%s'", 't', 'tid'), $type); + } + while ($item = db_fetch_object($result)) { + if (!isset($count[$type][$item->tid])) { + $count[$type][$item->tid] = array('own_nodes' => array()); + } + $count[$type][$item->tid]['own_nodes'][$item->nid] = 1; + } + } + + if (!isset($count[$type][$tid]['count_own'])) { + $modified = TRUE; + $count[$type][$tid]['count_own'] = count($count[$type][$tid]['own_nodes']); + $count[$type][$tid]['count_children'] = 0; + $count[$type][$tid]['children_nodes'] = array(); + foreach (_taxonomy_term_children($tid) as $c) { + if ($children = _directory_term_count_nodes($c, $type, FALSE)) { // FALSE: we do not need to save $count in the db at this iteration. + // Add the children's own nodes: + if (is_array($children['own_nodes'])) { + foreach ($children['own_nodes'] AS $child_nid => $n) { + if (!isset($count[$type][$tid]['own_nodes'][$child_nid])) { // make sure the nid is not already counted for the parent. + $count[$type][$tid]['children_nodes'][$child_nid] = 1; + } + } + } + // Add the nodes of the children's children. + if (is_array($children['children_nodes'])) { + foreach ($children['children_nodes'] AS $child_nid => $n) { + if (!isset($count[$type][$tid]['own_nodes'][$child_nid])) { // make sure the nid is not already counted for the parent. + $count[$type][$tid]['children_nodes'][$child_nid] = 1; + } + } + } + } + } + $count[$type][$tid]['count_children'] = count($count[$type][$tid]['children_nodes']); + } + + if ($modified && $save_to_db) { + $cache = serialize($count); + // the cached data will be used for at least one hour before being flushed. + // TODO, make the nb of seconds before this cache is cleared configurable: time() + variable_get(); + cache_set('taxonomy_term_count_nodes', 'cache_page', $cache, time() + 60 * 60); + } + + return $count[$type][$tid]; } /** @@ -305,27 +389,16 @@ function directory_term_page($str_tids = * An array of term IDs to match. * @param $operator * How to interpret multiple IDs in the array. Can be "or" or "and". - * @param $depth - * How many levels deep to traverse the taxonomy tree. Can be a nonnegative - * integer or "all". - * @param $limit - * The number of results to return. + * @param $pager + * How many nodes should be displayed per page, zero means no pager. + * @param $content_type + * Only the nodes of this content type should be retrieved + * @param $order + * The order clause for the query that retrieve the nodes. * @return * A resource identifier pointing to the query results. */ -function directory_select_nodes($tids = array(), $operator = 'or', $depth = 0, $limit = 15) { - $result = directory_select_nodes_query_builder($tids, $operator, $depth, $limit, 'fetch'); - return $result; -} - -function directory_select_count_nodes($tids = array(), $operator = 'or', $depth = 0, $limit = 15) { - return db_result(directory_select_nodes_query_builder($tids, $operator, $depth, $limit, 'count')); -} - -/** - * Private function for directory_select_nodes and directory_select_count_nodes - */ -function directory_select_nodes_query_builder($tids = array(), $operator = 'or', $depth = 0, $limit = 15, $query_type = 'fetch') { +function _directory_select_nodes($tids = array(), $operator = 'or', $pager = 10, $content_type = NULL, $order = 'n.sticky DESC, n.created DESC') { if (count($tids) > 0) { // For each term ID, generate an array of descendant term IDs to the right depth. $descendant_tids = array(); @@ -338,10 +411,22 @@ function directory_select_nodes_query_bu $descendant_tids[] = array_merge(array($tid), array_map('_taxonomy_get_tid_from_term', $tree)); } + if ($content_type) { + $content_type_where = "AND n.type = '". db_escape_string($content_type) ."' "; + } + else { + foreach (variable_get('directory_no_nodes', array()) as $content_type => $hide_nodes) { + if (!$hide_nodes) { + $enabled[] = "'$content_type'"; + } + } + $content_type_where = 'AND n.type IN ('. implode(',', $enabled) .') '; + } + if ($operator == 'or') { $str_tids = implode(',', call_user_func_array('array_merge', $descendant_tids)); - $sql_fetch = db_rewrite_sql('SELECT DISTINCT(n.nid), n.* FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $str_tids .') AND n.status = 1 ORDER BY n.sticky DESC, n.title ASC'); - $sql_count = db_rewrite_sql('SELECT COUNT(DISTINCT(n.nid)) FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $str_tids .') AND n.status = 1 ORDER BY n.sticky DESC, n.title ASC'); + $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created, n.type FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $str_tids .') AND n.status = 1 '. $content_type_where .'ORDER BY '. $order; + $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $str_tids .') AND n.status = 1 '. $content_type_where; } else { $joins = ''; @@ -350,276 +435,143 @@ function directory_select_nodes_query_bu $joins .= ' INNER JOIN {term_node} tn'. $index .' ON n.nid = tn'. $index .'.nid'; $wheres .= ' AND tn'. $index .'.tid IN ('. implode(',', $tids) .')'; } - $sql_fetch = db_rewrite_sql('SELECT DISTINCT(n.nid), n.* FROM {node} n '. $joins .' WHERE n.status = 1 '. $wheres .' ORDER BY n.sticky DESC, n.title ASC'); - $sql_count = db_rewrite_sql('SELECT COUNT(DISTINCT(n.nid)) FROM {node} n '. $joins .' WHERE n.status = 1 '. $wheres .' ORDER BY n.sticky DESC, n.title ASC'); + $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created, n.type FROM {node} n '. $joins .' WHERE n.status = 1 '. $content_type_where . $wheres .' ORDER BY '. $order; + $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n '. $joins .' WHERE n.status = 1 '. $content_type_where . $wheres; + } + $sql = db_rewrite_sql($sql); + $sql_count = db_rewrite_sql($sql_count); + if ($pager > 0) { + $result = pager_query($sql, $pager, 0, $sql_count); + } + else { + // If no pager is used, limit to 100 results. + $result = db_query_range($sql, 0, 100); } - - $sql = ($query_type == 'count') ? $sql_count : $sql_fetch; - $result = (is_numeric($limit)) ? db_query_range($sql, 0, $limit) : db_query($sql); } return $result; } -/** - * Load and goto a random directory link - */ -function directory_random() { - $nid = db_result(db_query('SELECT n.nid FROM {node} n WHERE n.status = 1 ORDER BY RAND() LIMIT 1')); - drupal_goto("node/$nid"); +function _directory_get_filter_content_types() { + $content_type_objects = node_get_types(); + $var = variable_get('directory_no_nodes', FALSE); + + // Create an array, with the content type names to filter by as keys and + // their corresponding full names as values. + if (!$var) { + foreach ($content_type_objects as $internal_name => $type) { + $content_types[$internal_name] = $type->name; + } + } + else { + foreach ($var as $content_type => $hide_nodes) { + if (!$hide_nodes) { + $content_types[$content_type] = $content_type_objects[$content_type]->name; + } + } + } + return $content_types; } -/******************************************************************** - * Drupal Hooks :: Themeable Functions - ********************************************************************/ +function _directory_remove_content_type_filter_from_url($url, $content_type) { + // Create a base drupal path that will be used in the theming function. + if ($url[strlen($url) - 1] == '/') { + $url = rtrim($url, '/'); + } -/** - * @addtogroup themeable - * @{ - */ + // Remove the current content type from the Drupal path query. + if ($content_type) { + $url = substr($url, 0, strrpos($url, '/')); + } -function theme_directory_listing($node) { - $node->teaser = ($node->teaser) ? "- $node->teaser" : $node->teaser; - return "
  • ". l($node->title, "node/$node->nid"). $node->teaser . "
  • \n"; + return $url; } -/** @} End of addtogroup themeable */ - -/******************************************************************** - * Module Specific :: Private Functions - ********************************************************************/ - /** - * Theme one section of the directory home page, corresponding to one vocabulary. - * There will be as many sections as there are vocabularies displayed on the home page. - * - * @param $vid - * integer: the vocabulary ID. + * Theme a vocabulary section. This typically shows the vocabulary tree, + * mentioning the number of nodes per term. * - * @param $collapse - * boolean: say if the vocabulary should follow the collapsed setting. - * if we are going to print only one vocabulary - * it would be bad design to have it collapsed. - * - * @return $output - * formatted html. + * @param $vocabulary + * A vocabulary object. + * @param $tree + * A tree generated by _directory_get_tree(). + * @param $collapsed + * Whether this vocabulary should be collapsed or not at the theme level. + * @param $title + * Whether this vocabulary should have a title above its tree or not. + * @return + * The rendered HTML. */ -function theme_directory_home_vocabulary($vid, $collapse = TRUE) { - $vocabulary = taxonomy_get_vocabulary($vid); - $terms = taxonomy_get_children(0, $vid); - - - $collapsed_vids = array(); - if ($collapse) { - $collapsed_vids = variable_get('directory_vocabularies_collapsed', array()); - } +function theme_directory_vocabulary($vocabulary, $tree = array(), $collapsed = TRUE, $title = TRUE, $content_type = NULL) { + static $js_added; - $collapsed_string = ''; - if (in_array($vid, $collapsed_vids)) { - $collapsed_string = 'directory-home-vocabulary-collapsed'; - } - drupal_add_js(drupal_get_path('module', 'directory') .'/directory.js'); - drupal_add_js("var toggleT = ". drupal_to_js(t('show / hide')) .';', 'inline'); - - $output = '
    '; - $output .= theme('directory_list_terms', $terms, t('By %vocabulary-name', array('%vocabulary-name' => $vocabulary->name))); - $output .= '
    '; - - return $output; -} - -/** - * Load all nodes found in a given tid - * - * We don't need static caching at this point since it is only called once per request. - */ -function directory_get_nodes_by_term($tid, $limit = NULL, $pager = FALSE) { - global $pager_count; - if (!is_numeric($pager_count)) $pager_count = 1; - $nodes = array(); - $where = ''; - - $skip_type = variable_get('directory_no_nodes', ''); - if (!empty($skip_type)) { - foreach ($skip_type as $type) { - $t[] = "'". db_escape_string($type) ."'"; - } - $where = 'AND n.type NOT IN ('. implode(",", $t) .')'; - } - - if ($tid == 'alpha') { - $sql = db_rewrite_sql('SELECT n.nid FROM {node} n INNER JOIN {term_node} t ON t.nid = n.nid WHERE 1 '. $where .' AND n.status = 1 ORDER BY n.sticky DESC, n.changed DESC'); - } - elseif ($tid == '0-9') { - $sql = db_rewrite_sql('SELECT n.nid FROM {node} n INNER JOIN {term_node} t ON t.nid = n.nid WHERE 1 '. $where ." AND n.status = 1 AND n.title REGEXP '^[0-9]' ORDER BY n.sticky DESC, n.changed DESC"); - } - elseif (preg_match('/^[a-zA-z]$/', $tid)) { - $sql = db_rewrite_sql('SELECT n.nid FROM {node} n INNER JOIN {term_node} t ON t.nid = n.nid WHERE 1 '. $where ." AND n.status = 1 AND n.title LIKE '". db_escape_string($tid) ."%' ORDER BY n.sticky DESC, n.changed DESC"); - } - else { - $sql = db_rewrite_sql('SELECT n.nid FROM {node} n INNER JOIN {term_node} t ON t.nid = n.nid WHERE 1 '. $where .' AND n.status = 1 AND t.tid = '. db_escape_string($tid) .' ORDER BY n.sticky DESC, n.changed DESC'); - } - if ($pager) { - $result = pager_query($sql, $limit, $pager_count); - $pager_count++; - } - else { - $result = $limit ? db_query_range($sql, 0, $limit) : db_query($sql); + if (!isset($js_added)) { + drupal_add_js(drupal_get_path('module', 'directory') .'/directory.js'); + drupal_add_js("var toggleT = ". drupal_to_js(t('show / hide')) .';', 'inline'); + $js_added = TRUE; } - while ($data = db_fetch_object($result)) { - $nodes[$data->nid] = node_load($data->nid); - $nids[] = $data->nid; - } - - /* Delete this if statement if using the above 'old way' */ - /* A very quick way of gathering taxonomy terms for the collected nodes. */ - if ($nids) { - $qqq='SELECT t.*, r.nid FROM {term_data} t, {term_node} r WHERE r.tid = t.tid AND r.nid IN ('. implode(', ', $nids) .') ORDER BY weight, name'; - $result = db_query($qqq); - while ($t = db_fetch_object($result)) { - $nodes[$t->nid]->taxonomy[$t->tid] = $t; + $collapsed_class = ''; + if ($collapsed) { + $collapsed_vids = variable_get('directory_vocabularies_collapsed', array()); + if (in_array($vocabulary->vid, $collapsed_vids)) { + $collapsed_class = 'directory-home-vocabulary-collapsed'; } } - return $nodes; -} + $hierarchy_class = ($vocabulary->hierarchy > 0) ? ' hierarchical-vocabulary' : ''; -/** - * Display the nodes related to a term. - * This function corresponds to the whole page, and will in turn call theme_directory_resource_section. - * - * @param $tid - * An integer ($term->tid) - * Or a string. See http://drupal.org/node/144743 and Alphabetical listing code block below. - * - * @param $filter - * either NULL or string 'vid'. If 'vid', terms will be filtered by that vid. - * See http://drupal.org/node/144743. - * - * @param $fid - * An integer corresponding to the vocabulary ID to filter by. - * - * @return $output - * formatted html. - */ -function theme_directory_resource($tid, $filter = null, $fid = null) { - global $pager_total; - global $pager_count; - $num_results_per_page = 100; - - /* Filters */ - if ($filter == 'vid' && is_numeric($fid)) { - /* Set the page heading to the term that's being filtered. */ - $term = taxonomy_get_term($tid); - $vocabulary = taxonomy_get_vocabulary($fid); - $title = "

    $term->name, by $vocabulary->name

    \n"; - $nodes = directory_get_nodes_by_term($tid, $num_results_per_page, true); - /* This is a container for nodes with no term matching the filter. We create an 'Other' category out of this. */ - $nodes_sans_terms = $nodes; - $taxonomy = taxonomy_get_tree($fid); - /* Iterate through the filter's terms and display resources that are linked to them */ - foreach ($taxonomy as $term) { - $node_by_term = null; - foreach ($nodes as $nid => $node) { - if ($node->taxonomy[$term->tid]) { - $node_by_term[$nid] = $node; - unset($nodes_sans_terms[$nid]); - } - } - $output .= theme('directory_resource_section', $node_by_term, $term); - } - - /* Create the fake 'Other' category */ - $term->tid = -1; - $term->name = t('General'); - $output .= theme('directory_resource_section', $nodes_sans_terms, $term); - - } - // Alphabetical listing - elseif (preg_match('/^[a-zA-z]$/', $tid) || $tid == 'alpha' || $tid == '0-9') { - if ($nodes = directory_get_nodes_by_term($tid, $num_results_per_page, true)) { - $node = _first($nodes); - $term = $node->taxonomy[$tid]; // mjc: nodes array is indexed by nid, not 0-based - $output = directory_toolbar_alpha($tid); - $output .= theme('directory_resource_section', $nodes, $term); - if ($pager = theme('pager', NULL, $num_results_per_page, $pager_count - 1)) { - $output .= $pager; - } - } - } - // Listing the nodes related to a single term. - elseif (is_numeric($tid)) { - $output = theme('directory_resource_sub_section', $tid); - if ($nodes = directory_get_nodes_by_term($tid, $num_results_per_page, true)) { - $node = _first($nodes); - $term = $node->taxonomy[$tid]; // MJC: was $nodes[0] which seems not to exist.. why? get_nodes_by_term uses nid as index into array! - $output .= theme('directory_resource_section', $nodes, $term); - } - else { - // FIXME: what is the use of this else{} block? We are returning $output, not $term! - $term = taxonomy_get_term($tid); - } + $path = "directory/vocabulary/$vocabulary->vid"; + if ($content_type) { + $path .= "/$content_type"; } + $title_content = (!$title) ? NULL : l(t('!vocabulary-name', array('!vocabulary-name' => $vocabulary->name)), $path); + $output = '
    '; + $output .= theme('directory_tree', $tree, $title_content, $content_type); + $output .= '
    '; return $output; } /** - * Display a box with links to the sub-categories - * This function only displays the shell (title +
    elements) where the links will be. - * It calls theme_directory_list_terms() which will print the content (list of links). - * - * @param $tid - * The term ID whose sub-categories must be displayed. + * Theme a tree. * + * @param $tree + * A tree generated by _directory_get_tree(). + * @param $title + * The title that will be used for this tree. A tree is typically presented + * as nested unordered list, so this title will be placed before the root + * unordered list. + * @param $content_type + * The content type to filter by. * @return - * formatted html + * The rendered HTML. */ -function theme_directory_resource_sub_section($tid) { - $output = ''; - - if ($terms = taxonomy_get_children($tid)) { - $output .= '
    '; - $output .= theme('directory_list_terms', $terms, t('Sub-categories')); - $output .= '
    '; - } - +function theme_directory_tree($tree = array(), $title = NULL, $content_type = NULL) { + $items = theme('directory_tree_helper', $tree, $content_type); + $output = theme('item_list', $items, $title); return $output; } /** - * Display a list of terms - * Each list item is a link to its corresponding term page. - * - * @param $terms - * An array of term objects. - * - * @param $title - * Translated text. - * - // FIXME: $parent not needed ?? beginner. - * @param $parent - * Display all the children whose parent tid is $parent. - * If we are on the main page, $parent = 0 and all terms within the vocabulary are displayed. - * If we are on a term page, $parent = $tid of that term and we display only the sub-terms. + * Helper function for theming a tree. * + * @param $tree + * A tree generated by _directory_get_tree(). + * @param $content_type + * The content type to filter by. * @return - * formatted html + * An array of (themed) items that can be used in (un)ordered lists. */ -function theme_directory_list_terms($terms, $title = '', $parent = 0) { - $output = ''; +function theme_directory_tree_helper($tree = array(), $content_type = NULL) { + $item_span = ''; $showcounts = variable_get('directory_show_child_counts', TRUE); - $hideempty = variable_get('directory_hide_empty_terms', FALSE); + $tree = ($tree != NULL) ? $tree : array(); - $item_span = ''; - - // Build a list of categories (taxonomy terms) and child counts. - foreach ($terms as $term) { - $nodecount = array('count_own' => 0, 'count_children' => 0); - if ($showcounts || $hideempty) { - $nodecount = directory_taxonomy_term_count_nodes($term->tid); - } + foreach ($tree as $term_meta) { + $nodecount = $term_meta['nodecount']; + $term = $term_meta['term']; + $children = $term_meta['children']; $nodecount_span = ''; if ($showcounts) { @@ -630,367 +582,89 @@ function theme_directory_list_terms($ter } } - // if desired, exclude items - if ((!$hideempty) || ($nodecount['count_own'] || $nodecount['count_children'])) { - $children = taxonomy_get_children($term->tid); - if (is_array($children)) { - $children = theme('directory_list_subterms', $children); - } - $items[] = array('data' => $item_span . l($term->name, "directory/$term->tid", (($term->description) ? array('title' => $term->description) : array())) . $nodecount_span . '', 'children' => $children); + $path = "directory/term/$term->tid"; + if ($content_type) { + $path .= "/$content_type"; } + $link = l($term->name, $path, (($term->description) ? array('title' => $term->description) : array())); + $items[] = array( + 'data' => $item_span . $link . $nodecount_span .'', + 'children' => theme_directory_tree_helper($children, $content_type) + ); } - - $output = theme('item_list', $items, $title); - return $output; + return $items; } /** - * Prints the number of nodes that belong to a term. + * Theme the number of nodes that belong to a term. * * @param $nodecount - * array returned by directory_taxonomy_term_count_nodes($term->tid) - * + * An array returned by _directory_term_count_nodes(). * @param $term - * term object that may be needed by some themes. - * + * A term object that may be needed by some themes. * @return - * either an empty string '' if there is nothing to display, - * or formatted HTML. - * + * The rendered HTML. */ function theme_directory_node_count($nodecount, $term) { - $output = " [". $nodecount['count_own']; + $output = ' ['. $nodecount['count_own']; $output .= $nodecount['count_children'] ? ' + '. $nodecount['count_children'] .']' : ']'; return $output; } /** - * Recursively display the sub-terms within a themed list - * - * @param $terms - * An array of term objects. + * Theme a node listing. * + * @param + * The db query result of _directory_select_nodes(). * @return - * array of elements to put in the themed list. + * The rendered HTML. */ -function theme_directory_list_subterms($terms) { - $showcounts = variable_get('directory_show_child_counts', TRUE); - $hideempty = variable_get('directory_hide_empty_terms', FALSE); - foreach ($terms as $term) { - $nodecount = 0; - if ($showcounts || $hideempty) { - $nodecount = directory_taxonomy_term_count_nodes($term->tid); +function theme_directory_term($result) { + if (db_num_rows($result) > 0) { + while ($node = db_fetch_object($result)) { + $items[] = l(t($node->title), "node/$node->nid"); } - $nodecount_span = ''; - if ($showcounts) { - $item_span = ''; - if ($nodecount['count_own'] || $nodecount['count_children']) { - $item_span = ''; - $nodecount_span = theme('directory_node_count', $nodecount, $term); - } - } - // if desired, exclude items - if ((!$hideempty) || ($nodecount['count_own'] || $nodecount['count_children'])) { - $children = NULL; - if ($get_children = taxonomy_get_children($term->tid)) { - $children = theme('directory_list_subterms', $get_children); - } - - $items[] = array('data' => $item_span . l($term->name, "directory/$term->tid", (($term->description) ? array('title' => $term->description) : array())) . $nodecount_span . '', 'children' => $children); - } - } - return $items; -} - -/** - * Display a term with all the nodes that belong in it. - * - * @param $nodes - * An array of nodes that belong to a given term (tid) - * - * @param $term - * Object representing a taxonomy term. - * - * @param $limit - * An integer used to only display n amount of resources instead of all resources for a category. - * - * @return - * HTML - */ -function theme_directory_resource_section($nodes, $term, $limit = 0) { - $output = ''; - if (!is_numeric($term->tid) || !$nodes) return NULL; - - $output .= "
      \n"; - - foreach ($nodes as $nid => $node) { - $output .= theme('directory_listing', $node); - } - - if ($limit) { - $num_nodes = directory_taxonomy_term_count_nodes($term->tid); - if ($num_nodes['count_own'] > $limit) { - $more = '
      '. t('%limit of %num_nodes showing in "%term".', array('%limit' => $limit, '%num_nodes' => $num_nodes['count_own'], '%term' => $term->name)). ' '. l(t('View all items.'), "directory/$term->tid"). "
      \n"; - } - } - $output .= "
    \n$more"; - - return $output; -} - -/** - * Set the title of a directory view as well as create the breadcrumb trail - * back to the directory root. - */ -function directory_set_breadcrumb($tid, $homepage_name = 'Home') { - $breadcrumb[] = l(t($homepage_name), ''); - $breadcrumb[] = l(t('browse'), 'directory'); - - $taxonomy = array_reverse(taxonomy_get_parents_all($tid)); - $term = array_pop($taxonomy); - $current_page = $term->name; - drupal_set_title($current_page); - - foreach($taxonomy as $term) { - $breadcrumb[] = l($term->name, "directory/$term->tid"); + $output .= theme('item_list', $items); + $output .= theme('pager', NULL, $pager, 0); } - if ($current_page) { - $breadcrumb[] = "$current_page"; - } - - drupal_set_breadcrumb($breadcrumb); -} - -/** - * Return a navigaton toolbar for alphatical directory browsing. - */ -function directory_toolbar_alpha($current_letter) { - $letters = array('0-9', 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O', - 'P','Q','R','S','T','U','V','W','X','Y','Z'); - foreach ($letters as $letter) { - $items[] = l($letter, 'directory/'. strtolower($letter), (strtoupper($current_letter) == $letter ? array('class' => 'active') : array())); - } - - return '
    '. implode(' ', $items) .'
    '; -} - -/** - * Create the filter links to sort a directory by another vocabulary. - */ -function directory_filters_toolbar($uri) { - $output = ''; - - $uri_array = explode('/', $uri); - foreach ($uri_array as $key => $part) { - if ($part == 'directory' || $part == 'eiir_search' && is_numeric($uri_array[$key + 1])) { - $tid = $uri_array[$key + 1]; - $clean_uri = $part .'/'. $tid; - $current_filter = trim(str_replace($clean_uri, '', $uri), '/'); - } - } - - if ($clean_uri && $tid) { - foreach (taxonomy_get_vocabularies() as $v) { - $valid_filters[$v->name] = "vid/$v->vid"; - } - - $vid = db_result(db_query('SELECT vid FROM {term_data} WHERE tid = %d', $tid)); - $hide_filter = "vid/$vid"; - $current_filter = (!$current_filter) ? 'alpha' : $current_filter; - - $output = '
    '. t('Sort by:
    '); - foreach ($valid_filters as $name => $filter_params_as_uri) { - if ($hide_filter != $filter_params_as_uri) { - if (strstr($current_filter, $filter_params_as_uri)) { - $links[] = ' '. t("$name"); - } - else { - $new_uri = $clean_uri; - if ($filter_params_as_uri != 'alpha') { - $new_uri .= '/'. $filter_params_as_uri; - } - - $url = url($new_uri); - $links[] = ' '. l($name, $url); - } - } - } - $output .= implode('
    ', $links). '
    '; + else { + $output .= '

    '. t('There are currently no posts in this category.') .'

    '; } - return $output; } /** - * Format a summary of the current pager position, such as "6 through 10 of 52". + * Theme the content type filters section. * - * @param $limit - * The number of query results to display per page. - * @param $element - * An optional integer to distinguish between multiple pagers on one page. - * @param $format - * A printf-style format string for customizing the pager text. + * @param $content_type + * The content type by which is currently being filtered. * @return - * An HTML string that generates this piece of the query pager. - * - * @ingroup themeable + * The rendered HTML. */ -function theme_directory_pager_detail($limit, $element = 0, $format = '%d through %d of %d.') { - global $pager_from_array, $pager_total; - - $output = '
    '; - if ($pager_total[$element] > (int)$pager_from_array[$element] + 1) { - $output .= sprintf($format, (int)$pager_from_array[$element] + 1, ((int)$pager_from_array[$element] + $limit <= $pager_total[$element] ? (int)$pager_from_array[$element] + $limit : $pager_total[$element]), $pager_total[$element]); - } - $output .= '
    '; - - return $output; -} - -/** - * Get the first element of an array - */ -function &_first(&$array) { - if (!is_array($array)) - return null; - if (!count($array)) - return false; // like reset() - reset($array); - return $array[key($array)]; -} - -/** - * Get last element of an array - */ -function &_last(&$array) { - if (!is_array($array)) - return null; - if (!count($array)) - return false; // like end() - end($array); - return $array[key($array)]; -} - -/** - * This is a replacement function for taxonomy_term_count_nodes. - * See: http://drupal.org/node/144969 (drupal issue) - * and: http://drupal.org/node/145023 (directory issue). - * - * Count the number of published nodes classified by a term. - * - * @param $tid - * The term's ID - * - * @param $type - * The $node->type. If given, taxonomy_term_count_nodes only counts - * nodes of $type that are classified with the term $tid. - * - * @param $save_to_db - * This function is recursive, and we don't need to save the result in the DB at each iteration. - * $save_to_db is set to FALSE at each nested call, so that the actual saving to DB can happen only - * when the function exits the last time. - * - * @return $array - * where: - * $array['count_own'] being the number of nodes within the term proper. - * $array['count_children'] being the number of nodes in children terms, not counting those which are already counted in the parent term. - * $array['own_nodes'] array of nid's within this $tid. - * $array['children_nodes'] array of all the descendent nid's from children terms, not including those already set as one's own. - * - * Results are statically cached. - * Also, in order to improve performance accross requests, we cache the serialized array on database, in {cache_page} (this table is flushed each time a node or a taxonomy item is added/updated/deleted). - */ -function directory_taxonomy_term_count_nodes($tid, $type = 0, $save_to_db = TRUE) { - static $count = array(); - $modified = FALSE; // We keep track of modification of $count, to check whether we need to save it to DB. - - if (empty($count)) { - $count = cache_get('taxonomy_term_count_nodes', 'cache_page'); - $count = unserialize($count->data); - } +function theme_directory_content_type_filters($content_type) { + $output = ''; - if (!isset($count[$type])) { - $modified = TRUE; - $count[$type] = array(); - // In the queries below, we cannot use 'SELECT t.tid, COUNT(n.nid) AS c FROM ...' - // because a node may be assigned more than one term and be counted more than once. - // We therefore take note of the nid's and count the number of items in the $count array, - // making sure there is no duplicate. - - // $type == 0 always evaluates TRUE if $type is a string - if (is_numeric($type)) { - $result = db_query(db_rewrite_sql('SELECT t.tid, n.nid FROM {term_node} t JOIN {node} n ON t.nid = n.nid WHERE n.status = 1', 't', 'tid')); - } - else { - $result = db_query(db_rewrite_sql("SELECT t.tid, n.nid FROM {term_node} t JOIN {node} n ON t.nid = n.nid WHERE n.status = 1 AND n.type = '%s'", 't', 'tid'), $type); - } - while ($item = db_fetch_object($result)) { - if (!isset($count[$type][$item->tid])) { - $count[$type][$item->tid] = array('own_nodes' => array()); - } - $count[$type][$item->tid]['own_nodes'][$item->nid] = 1; - } - } + $content_types = _directory_get_filter_content_types(); + $base_drupal_path = _directory_remove_content_type_filter_from_url($_GET['q'], $content_type); - if (!isset($count[$type][$tid]['count_own'])) { - $modified = TRUE; - $count[$type][$tid]['count_own'] = count($count[$type][$tid]['own_nodes']); - $count[$type][$tid]['count_children'] = 0; - $count[$type][$tid]['children_nodes'] = array(); - foreach (_taxonomy_term_children($tid) as $c) { - if ($children = directory_taxonomy_term_count_nodes($c, $type, FALSE)) { // FALSE: we do not need to save $count in the db at this iteration. - // Add the children's own nodes: - if (is_array($children['own_nodes'])) { - foreach ($children['own_nodes'] AS $child_nid => $n) { - if (!isset($count[$type][$tid]['own_nodes'][$child_nid])) { // make sure the nid is not already counted for the parent. - $count[$type][$tid]['children_nodes'][$child_nid] = 1; - } - } - } - // Add the nodes of the children's children. - if (is_array($children['children_nodes'])) { - foreach ($children['children_nodes'] AS $child_nid => $n) { - if (!isset($count[$type][$tid]['own_nodes'][$child_nid])) { // make sure the nid is not already counted for the parent. - $count[$type][$tid]['children_nodes'][$child_nid] = 1; - } - } - } - } - } - $count[$type][$tid]['count_children'] = count($count[$type][$tid]['children_nodes']); - } + $output .= '
    '; - if ($modified && $save_to_db) { - $cache = serialize($count); - // the cached data will be used for at least one hour before being flushed. - // TODO, make the nb of seconds before this cache is cleared configurable: time() + variable_get(); - cache_set('taxonomy_term_count_nodes', 'cache_page', $cache, time() + 60 * 60); + $output .= '

    '. t("Filter by content type") .'

    '; + $output .= l(t('No filter'), $base_drupal_path, array('class' => 'directory-content-type-filter-link')); + foreach ($content_types as $internal_name => $full_name) { + $output .= l($full_name, $base_drupal_path .'/'. $internal_name, array('class' => 'directory-content-type-filter-link')); } - return $count[$type][$tid]; -} - -/** - * Menu callback for directory/vocabulary. - * - * @param $vid - * the vocabulary ID. - */ -function directory_vocabulary_page($vid = '') { - $output = ''; - - // If we don't have a real vocabulary ID, redirect to the main directory page. - if (empty($vid) || !is_numeric($vid)) { - drupal_goto('directory'); + $output .= '

    '; + if ($content_type) { + $type = node_get_types('type', $content_type); + $output .= t('Current filter: %content-type.', array('%content-type' => $type->name)); } else { - $vocabulary = taxonomy_get_vocabulary($vid); - if (!$vocabulary) { - drupal_goto('directory'); - } - drupal_set_title(t("Directory for @vocabulary", array('@vocabulary' => $vocabulary->name))); - $output .= theme_directory_home_vocabulary($vid, FALSE); + $output .= t('Current filter: none.'); } + + $output .= '

    '; + return $output; } -